<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://shantoroy.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://shantoroy.com/" rel="alternate" type="text/html" /><updated>2025-04-13T21:07:21+00:00</updated><id>https://shantoroy.com/feed.xml</id><title type="html">Roy’s Blog</title><subtitle>Research, Education, Travel, and Personal Thoughts.</subtitle><author><name>Shanto Roy</name></author><entry><title type="html">Certification Preparation Question Bank – Practice &amp;amp; Contribute</title><link href="https://shantoroy.com/certification/certification-preparation-practice-questions/" rel="alternate" type="text/html" title="Certification Preparation Question Bank – Practice &amp;amp; Contribute" /><published>2025-03-25T00:00:00+00:00</published><updated>2025-03-25T00:00:00+00:00</updated><id>https://shantoroy.com/certification/certification-preparation-practice-questions</id><content type="html" xml:base="https://shantoroy.com/certification/certification-preparation-practice-questions/"><![CDATA[<h2 id="about-the-cert-preparation-question-bank">About the Cert Preparation Question Bank</h2>

<p>The <a href="https://shantoroy.com/certprep/"><strong>Certification Preparation Question Bank</strong></a> is an open-source question bank project designed to help learners practice for various certification exams. Currently, it is in <strong>beta mode</strong>, and I’ll try to actively expand the question sets.</p>

<p>Unlike traditional exam simulations, this platform focuses on <strong>practice mode</strong>, allowing users to go through questions at their own pace, review answers, and learn effectively.</p>

<h2 id="currently-available-certification-exams">Currently Available Certification Exams</h2>

<p>We are continuously adding new certifications, but as of now, the following exams are included in the question bank:</p>

<ul>
  <li><strong>AWS AI Practitioner</strong></li>
  <li>(More to come – stay tuned!)</li>
</ul>

<p>If you are preparing for these certifications, you can start practicing right away!</p>

<h2 id="how-to-contribute">How to Contribute</h2>

<p>This project is open-source, and contributions from the community are highly encouraged! You can help by adding new questions, improving existing ones, or expanding the explanations.</p>

<h3 id="steps-to-contribute">Steps to Contribute:</h3>
<ol>
  <li>Visit the GitHub repository: <a href="https://github.com/shantoroy/cert-prep-question-bank">Certification Preparation Question Bank</a></li>
  <li>Follow the contribution guidelines in the <code class="language-plaintext highlighter-rouge">README.md</code> file.</li>
  <li>Add new questions to the relevant JSON files. You can use <a href="https://github.com/shantoroy/certprep-question-bank-helper">This Tool</a> to make life easier.</li>
  <li>Create a new question bank by creating a JSON file for a Cert.</li>
  <li>Submit a Pull Request (PR) for review.</li>
</ol>

<p>Your contributions will help build a valuable learning resource for many aspiring professionals.</p>

<h2 id="supporting-the-project">Supporting the Project</h2>

<p>If you find this project useful, consider supporting it in the following ways:</p>
<ul>
  <li><strong>Contribute Questions</strong> – Help expand the question bank!</li>
  <li><strong>Spread the Word</strong> – Share it with others who are preparing for certifications.</li>
  <li><strong>Donate</strong> – Your donations will help sustain and grow the project.</li>
</ul>

<div style="display: flex; justify-content: center; gap: 20px; flex-wrap: wrap; padding: 20px;">

<!-- Buy Me a Coffee -->

<div>

<script type="text/javascript" src="https://cdnjs.buymeacoffee.com/1.0.0/button.prod.min.js" data-name="bmc-button" data-slug="shantoroy" data-color="#FFDD00" data-emoji="" data-font="Cookie" data-text="Buy me a coffee" data-outline-color="#000000" data-font-color="#000000" data-coffee-color="#ffffff">

</script>

</div>

<!-- Pay with PayPal -->

<div>

<style>

.paypal-sponsor-button {

background-color: #FFC439;

color: #111;

border: none;

border-radius: 5px;

padding: 10px  20px;

font-size: 16px;

font-weight: bold;

cursor: pointer;

display: inline-flex;

align-items: center;

gap: 8px;

transition: background-color 0.3s;

}

.paypal-sponsor-button:hover {

background-color: #F2BB36;

}

.paypal-sponsor-button  img {

height: 20px;

}

</style>

<form action="https://www.paypal.com/donate?business=Q9F45GULUSYMY&amp;currency_code=USD" method="post" target="_blank">


<button type="submit" class="paypal-sponsor-button">

<img src="https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-100px.png" alt="PayPal Logo" />

Sponsor Me

</button>

</form>

</div>

<div>

</div>

## What's Next?

Since this is an evolving project, we plan to:
- Expand the list of certification exams.
- Enhance the user experience.
- Introduce more features based on user feedback.

If you have suggestions, feel free to open an issue in the GitHub repository.

Stay tuned for updates, and happy learning!

<!--stackedit_data:
eyJoaXN0b3J5IjpbLTEzNTk1MDM2ODEsMTQzNjgxNTU0NSwtMT
I3ODMwMTExMiwtMzg1Mzk3NDg1LC0zOTM5MDQ5NjMsLTE1MzQw
Nzg4OTMsLTE3MDA0NDMzNzksMjc2ODM2NDExXX0=
-->
</div>]]></content><author><name>Shanto Roy</name></author><category term="Certification" /><category term="Certification" /><category term="Practice Questions" /><category term="Open Source" /><category term="Contribute" /><category term="DevOps" /><category term="Cloud" /><summary type="html"><![CDATA[Introducing our certification preparation question bank, currently in beta! Practice for your exams and contribute to the project.]]></summary></entry><entry><title type="html">#100DaysOfSRE (Day 36): Kubernetes Helm Charts – Package &amp;amp; Deploy Applications</title><link href="https://shantoroy.com/kubernetes/kubernetes-helm-charts-to-package-deploy-app/" rel="alternate" type="text/html" title="#100DaysOfSRE (Day 36): Kubernetes Helm Charts – Package &amp;amp; Deploy Applications" /><published>2025-03-16T00:00:00+00:00</published><updated>2025-03-16T00:00:00+00:00</updated><id>https://shantoroy.com/kubernetes/kubernetes-helm-charts-to-package-deploy-app</id><content type="html" xml:base="https://shantoroy.com/kubernetes/kubernetes-helm-charts-to-package-deploy-app/"><![CDATA[<p><a href="https://helm.sh/">Helm</a>  is a package manager for Kubernetes that simplifies the deployment and management of applications. Helm uses  <strong>Helm charts</strong>, which are collections of preconfigured Kubernetes resources (e.g., deployments, services, config maps) packaged together. Here’s why Helm charts are beneficial for Kubernetes application deployment:</p>

<hr />

<h4 id="1--simplifies-application-deployment">1.  <strong>Simplifies Application Deployment</strong></h4>

<ul>
  <li>
    <p>Helm charts provide a single, versioned package for deploying complex applications.</p>
  </li>
  <li>
    <p>Instead of managing multiple YAML files, you can deploy an application with a single command:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm <span class="nb">install </span>my-app ./my-chart
</code></pre></div>    </div>
  </li>
</ul>

<h4 id="2--reusability">2.  <strong>Reusability</strong></h4>

<ul>
  <li>
    <p>Helm charts are reusable across environments (e.g., dev, staging, production).</p>
  </li>
  <li>
    <p>You can create a chart once and use it for multiple deployments with different configurations.</p>
  </li>
</ul>

<h4 id="3--parameterization">3.  <strong>Parameterization</strong></h4>

<ul>
  <li>
    <p>Helm charts support  <strong>values.yaml</strong>  files, which allow you to customize deployments without modifying the chart itself.</p>
  </li>
  <li>
    <p>Example:</p>

    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># values.yaml</span>
<span class="na">replicaCount</span><span class="pi">:</span> <span class="m">3</span>
<span class="na">image</span><span class="pi">:</span>
  <span class="na">repository</span><span class="pi">:</span> <span class="s">my-app</span>
  <span class="na">tag</span><span class="pi">:</span> <span class="s">latest</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>You can override these values during installation:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm <span class="nb">install </span>my-app ./my-chart <span class="nt">--set</span> <span class="nv">replicaCount</span><span class="o">=</span>5
</code></pre></div>    </div>
  </li>
</ul>

<h4 id="4--versioning">4.  <strong>Versioning</strong></h4>

<ul>
  <li>
    <p>Helm charts are versioned, making it easy to roll back to a previous version if something goes wrong:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm rollback my-app 1.0.0
</code></pre></div>    </div>
  </li>
</ul>

<h4 id="5--dependency-management">5.  <strong>Dependency Management</strong></h4>

<ul>
  <li>
    <p>Helm charts can define dependencies on other charts, simplifying the deployment of multi-component applications.</p>
  </li>
  <li>
    <p>Example: A web application chart might depend on a Redis or PostgreSQL chart.</p>
  </li>
</ul>

<h4 id="6--community-and-ecosystem">6.  <strong>Community and Ecosystem</strong></h4>

<ul>
  <li>
    <p>Helm has a large community and a rich ecosystem of prebuilt charts available in the  <a href="https://artifacthub.io/">Artifact Hub</a>.</p>
  </li>
  <li>
    <p>You can use these charts to deploy popular applications (e.g., Prometheus, Grafana, WordPress) with minimal effort.</p>
  </li>
</ul>

<h4 id="7--standardization">7.  <strong>Standardization</strong></h4>

<ul>
  <li>Helm provides a standardized way to package and deploy applications, making it easier for teams to collaborate and share configurations.</li>
</ul>

<h4 id="8--lifecycle-management">8.  <strong>Lifecycle Management</strong></h4>

<ul>
  <li>Helm supports lifecycle hooks (e.g., pre-install, post-upgrade) to execute custom logic during deployment.</li>
</ul>

<hr />

<h2 id="usability">Usability</h2>
<h3 id="example-workflow-with-helm"><strong>Example Workflow with Helm</strong></h3>

<ol>
  <li>
    <p>Develop a Helm chart for your application.</p>
  </li>
  <li>
    <p>Store the chart in a version control system (e.g., Git).</p>
  </li>
  <li>
    <p>Use Helm to deploy the application to different environments (e.g., dev, staging, production) with environment-specific configurations.</p>
  </li>
  <li>
    <p>Monitor and update the application using Helm’s upgrade and rollback features.</p>
  </li>
</ol>

<h3 id="challenges-of-not-using-helm-charts"><strong>Challenges of Not Using Helm Charts</strong></h3>

<ol>
  <li>
    <p>Manual YAML Management:</p>

    <ul>
      <li>
        <p>Without Helm, teams must manually manage multiple YAML files for deployments, services, config maps, etc.</p>
      </li>
      <li>
        <p>This can be error-prone and time-consuming, especially for complex applications.</p>
      </li>
    </ul>
  </li>
  <li>
    <p>Lack of Standardization:</p>

    <ul>
      <li>Each team might use its own approach to deploying applications, leading to inconsistencies and inefficiencies.</li>
    </ul>
  </li>
  <li>
    <p>Difficulty in Reusability:</p>

    <ul>
      <li>Without Helm, reusing configurations across environments or applications becomes challenging, leading to duplication of effort.</li>
    </ul>
  </li>
  <li>
    <p>No Versioning:</p>

    <ul>
      <li>Without Helm, there’s no built-in versioning for application configurations, making it harder to track changes and roll back to previous versions.</li>
    </ul>
  </li>
  <li>
    <p>Complex Dependency Management:</p>

    <ul>
      <li>Managing dependencies (e.g., databases, message queues) becomes more complex without Helm’s dependency management features.</li>
    </ul>
  </li>
  <li>
    <p>Limited Ecosystem Integration:</p>

    <ul>
      <li>Without Helm, companies miss out on the rich ecosystem of prebuilt charts and community support.</li>
    </ul>
  </li>
</ol>

<h3 id="example-workflow-without-helm"><strong>Example Workflow Without Helm</strong></h3>

<ol>
  <li>
    <p>Manually create and manage YAML files for each Kubernetes resource.</p>
  </li>
  <li>
    <p>Copy and modify YAML files for different environments, increasing the risk of errors.</p>
  </li>
  <li>
    <p>Deploy applications using  <code class="language-plaintext highlighter-rouge">kubectl apply</code>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> deployment.yaml <span class="nt">-f</span> service.yaml <span class="nt">-f</span> configmap.yaml
</code></pre></div>    </div>
  </li>
  <li>
    <p>Manually track changes and roll back deployments if necessary.</p>
  </li>
</ol>

<h3 id="when-should-a-company-use-helm-charts">When Should a Company Use Helm Charts?</h3>

<ul>
  <li>
    <p><strong>Complex Applications</strong>: If your application has multiple components (e.g., microservices, databases, message queues), Helm simplifies deployment and management.</p>
  </li>
  <li>
    <p><strong>Multi-Environment Deployments</strong>: If you deploy applications to multiple environments (e.g., dev, staging, production), Helm ensures consistency and reusability.</p>
  </li>
  <li>
    <p><strong>Frequent Updates</strong>: If your application requires frequent updates, Helm’s versioning and rollback features are invaluable.</p>
  </li>
  <li>
    <p><strong>Team Collaboration</strong>: If multiple teams are involved in deploying and managing applications, Helm provides a standardized approach.</p>
  </li>
</ul>

<hr />

<h2 id="hands-on">Hands-on</h2>
<h3 id="step-1-install-helm">Step 1: Install Helm</h3>

<p>Ensure Helm is installed before proceeding.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-fsSL</span> https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
</code></pre></div></div>

<p>Verify the installation:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm version
</code></pre></div></div>

<hr />

<h3 id="step-2-create-a-helm-chart">Step 2: Create a Helm Chart</h3>

<p>Let’s create a Helm chart for a simple <strong>Node.js app with PostgreSQL</strong>.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm create myapp <span class="nb">cd </span>myapp
</code></pre></div></div>

<p>This creates a folder structure like:</p>

<pre><code class="language-pgsql">myapp/
├── charts/
├── templates/
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── _helpers.tpl
│   ├── NOTES.txt
├── values.yaml
├── Chart.yaml
</code></pre>

<hr />

<h3 id="step-3-define-application-configuration">Step 3: Define Application Configuration</h3>

<p>Modify <code class="language-plaintext highlighter-rouge">Chart.yaml</code> with details:</p>

<p><strong><code class="language-plaintext highlighter-rouge">Chart.yaml</code></strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v2</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">description</span><span class="pi">:</span> <span class="s">A Helm chart for deploying a Node.js app with PostgreSQL</span>
<span class="na">version</span><span class="pi">:</span> <span class="s">1.0.0</span>
<span class="na">appVersion</span><span class="pi">:</span> <span class="s2">"</span><span class="s">1.0"</span>
</code></pre></div></div>

<p><strong><code class="language-plaintext highlighter-rouge">values.yaml</code></strong> (customizable settings)</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">replicaCount</span><span class="pi">:</span> <span class="m">2</span>

<span class="na">image</span><span class="pi">:</span>
  <span class="na">repository</span><span class="pi">:</span> <span class="s">mydockerhub/myapp</span>
  <span class="na">tag</span><span class="pi">:</span> <span class="s">latest</span>
  <span class="na">pullPolicy</span><span class="pi">:</span> <span class="s">IfNotPresent</span>

<span class="na">service</span><span class="pi">:</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">ClusterIP</span>
  <span class="na">port</span><span class="pi">:</span> <span class="m">80</span>

<span class="na">ingress</span><span class="pi">:</span>
  <span class="na">enabled</span><span class="pi">:</span> <span class="no">false</span>

<span class="na">postgresql</span><span class="pi">:</span>
  <span class="na">enabled</span><span class="pi">:</span> <span class="no">true</span>
  <span class="na">username</span><span class="pi">:</span> <span class="s">admin</span>
  <span class="na">password</span><span class="pi">:</span> <span class="s">secret</span>
  <span class="na">database</span><span class="pi">:</span> <span class="s">myappdb</span>
</code></pre></div></div>

<hr />

<h3 id="step-4-define-kubernetes-resources">Step 4: Define Kubernetes Resources</h3>

<p><strong><code class="language-plaintext highlighter-rouge">templates/deployment.yaml</code></strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">-app</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> 
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> 
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> 
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">myapp</span>
        <span class="na">image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">:"</span>
        <span class="na">ports</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">3000</span>
</code></pre></div></div>

<p><strong><code class="language-plaintext highlighter-rouge">templates/service.yaml</code></strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">-service</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">type</span><span class="pi">:</span> 
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> 
  <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>
      <span class="na">port</span><span class="pi">:</span> 
      <span class="na">targetPort</span><span class="pi">:</span> <span class="m">3000</span>
</code></pre></div></div>

<hr />

<h3 id="step-5-deploy-the-helm-chart">Step 5: Deploy the Helm Chart</h3>

<h4 id="1️⃣-package-the-chart"><strong>1️⃣ Package the Chart</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm package myapp
</code></pre></div></div>

<h4 id="2️⃣-install-the-chart"><strong>2️⃣ Install the Chart</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm <span class="nb">install </span>myapp ./myapp
</code></pre></div></div>

<h4 id="3️⃣-list-deployed-charts"><strong>3️⃣ List Deployed Charts</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm list
</code></pre></div></div>

<h4 id="4️⃣-check-running-services"><strong>4️⃣ Check Running Services</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get pods
kubectl get svc
</code></pre></div></div>

<h4 id="5️⃣-uninstall-the-chart"><strong>5️⃣ Uninstall the Chart</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm uninstall myapp
</code></pre></div></div>

<hr />

<h3 id="step-6-helm-repositories--chart-distribution">Step 6: Helm Repositories &amp; Chart Distribution</h3>

<h4 id="1️⃣-add-a-helm-repository"><strong>1️⃣ Add a Helm Repository</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm repo add bitnami https://charts.bitnami.com/bitnami
helm search repo bitnami
</code></pre></div></div>

<h4 id="2️⃣-upgrade-a-helm-release"><strong>2️⃣ Upgrade a Helm Release</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm upgrade myapp ./myapp
</code></pre></div></div>

<h4 id="3️⃣-rollback-to-a-previous-version"><strong>3️⃣ Rollback to a Previous Version</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm rollback myapp 1
</code></pre></div></div>

<hr />

<h2 id="remarks">Remarks</h2>

<p>Using <strong>Helm charts</strong> for Kubernetes application deployment offers significant advantages in terms of simplicity, reusability, parameterization, versioning, and standardization.</p>

<p>Companies that adopt Helm can streamline their deployment processes, reduce errors, and improve collaboration. On the other hand, not using Helm can lead to manual, error-prone, and inconsistent deployment workflows, especially for complex applications.</p>

<p>For most organizations, especially those managing large-scale or complex Kubernetes deployments, Helm is a highly recommended tool.</p>

<p><strong>Key Takeaways:</strong><br />
✅ Helm simplifies Kubernetes deployments with reusable templates.<br />
✅ It provides versioning, rollback, and environment-based configurations.<br />
✅ Helm Charts can package complex applications with dependencies.</p>

<p><strong>What’s Next?</strong><br />
🔹 <strong>Day 37</strong>: Kubernetes Security Best Practices<br />
🔹 <strong>Day 38</strong>: Scaling Kubernetes Applications with Horizontal Pod Autoscaler</p>

<!--stackedit_data:
eyJoaXN0b3J5IjpbLTQzMzkzNzY0NSwtMTY3NDA0NTQ5MV19
-->]]></content><author><name>Shanto Roy</name></author><category term="Kubernetes" /><category term="Kubernetes" /><category term="Helm" /><category term="DevOps" /><category term="SRE" /><category term="CI/CD" /><category term="Kubernetes Package Management" /><summary type="html"><![CDATA[Learn how to use Helm Charts for managing Kubernetes applications efficiently.]]></summary></entry><entry><title type="html">#100DaysOfSRE (Day 35): Kubernetes CI/CD Pipeline with GitHub Actions &amp;amp; ArgoCD</title><link href="https://shantoroy.com/kubernetes/kubernetes-ci-cd-with-github-actions-argocd/" rel="alternate" type="text/html" title="#100DaysOfSRE (Day 35): Kubernetes CI/CD Pipeline with GitHub Actions &amp;amp; ArgoCD" /><published>2025-03-15T00:00:00+00:00</published><updated>2025-03-15T00:00:00+00:00</updated><id>https://shantoroy.com/kubernetes/kubernetes-ci-cd-with-github-actions-argocd</id><content type="html" xml:base="https://shantoroy.com/kubernetes/kubernetes-ci-cd-with-github-actions-argocd/"><![CDATA[<p>Combining  <strong>GitHub Actions</strong>  and  <strong>Argo CD</strong>  for CI/CD on Kubernetes is a powerful and modern approach that leverages the strengths of both tools. Here’s why this combination is a proper choice:</p>

<hr />

<h2 id="github-actions-for-ci-continuous-integration"><strong>GitHub Actions for CI (Continuous Integration)</strong></h2>

<p>GitHub Actions is a robust CI/CD platform integrated directly into GitHub repositories. It excels at automating build, test, and packaging workflows. Here’s why it’s great for CI:</p>

<h4 id="a--tight-integration-with-github">a.  <strong>Tight Integration with GitHub</strong></h4>

<ul>
  <li>
    <p>GitHub Actions is natively integrated into GitHub, making it easy to trigger workflows based on repository events (e.g., push, pull request, release).</p>
  </li>
  <li>
    <p>No need for external CI tools; everything is managed within GitHub.</p>
  </li>
</ul>

<h4 id="b--extensive-ecosystem">b.  <strong>Extensive Ecosystem</strong></h4>

<ul>
  <li>
    <p>GitHub Actions has a large marketplace of prebuilt actions for common tasks (e.g., building Docker images, running tests, deploying to cloud providers).</p>
  </li>
  <li>
    <p>You can easily extend workflows with custom actions.</p>
  </li>
</ul>

<h4 id="c--scalability">c.  <strong>Scalability</strong></h4>

<ul>
  <li>GitHub Actions supports parallel jobs and matrix builds, enabling efficient testing across multiple environments or configurations.</li>
</ul>

<h4 id="d--artifact-management">d.  <strong>Artifact Management</strong></h4>

<ul>
  <li>
    <p>GitHub Actions can build and push Docker images to container registries (e.g., Docker Hub, GitHub Container Registry, AWS ECR).</p>
  </li>
  <li>
    <h2 id="it-can-also-generate-and-store-build-artifacts-eg-binaries-helm-charts">It can also generate and store build artifacts (e.g., binaries, Helm charts).</h2>
  </li>
</ul>

<h2 id="why-combine-github-actions-and-argo-cd"><strong>Why Combine GitHub Actions and Argo CD?</strong></h2>

<h4 id="a--separation-of-concerns">a.  <strong>Separation of Concerns</strong></h4>

<ul>
  <li>
    <p><strong>GitHub Actions</strong>  handles the CI part: building, testing, and packaging applications.</p>
  </li>
  <li>
    <p><strong>Argo CD</strong>  handles the CD part: deploying and managing applications in Kubernetes.</p>
  </li>
  <li>
    <p>This separation ensures that each tool focuses on its strengths.</p>
  </li>
</ul>

<h4 id="b--end-to-end-automation">b.  <strong>End-to-End Automation</strong></h4>

<ul>
  <li>
    <p>GitHub Actions can trigger Argo CD to deploy applications after a successful build.</p>
  </li>
  <li>
    <p>This creates a fully automated pipeline from code commit to production deployment.</p>
  </li>
</ul>

<h4 id="c--gitops-workflow">c.  <strong>GitOps Workflow</strong></h4>

<ul>
  <li>
    <p>GitHub Actions pushes changes (e.g., Docker images, Helm charts) to Git repositories.</p>
  </li>
  <li>
    <p>Argo CD picks up these changes and deploys them to Kubernetes, ensuring a GitOps workflow.</p>
  </li>
</ul>

<h4 id="d--scalability-and-flexibility">d.  <strong>Scalability and Flexibility</strong></h4>

<ul>
  <li>
    <p>GitHub Actions scales well for CI tasks, while Argo CD scales for managing complex Kubernetes deployments.</p>
  </li>
  <li>
    <p>Both tools are highly flexible and can be customized to fit your workflow.</p>
  </li>
</ul>

<h4 id="e--auditability-and-traceability">e.  <strong>Auditability and Traceability</strong></h4>

<ul>
  <li>
    <p>All changes are tracked in Git, providing a clear audit trail and enabling rollbacks.</p>
  </li>
  <li>
    <p>GitHub Actions logs and Argo CD’s synchronization history provide visibility into the pipeline.</p>
  </li>
</ul>

<hr />

<h3 id="4--example-workflow-github-actions--argo-cd">4.  <strong>Example Workflow: GitHub Actions + Argo CD</strong></h3>

<p>Here’s how the two tools can work together in a CI/CD pipeline:</p>

<ol>
  <li>
    <p><strong>Code Push</strong>:</p>

    <ul>
      <li>A developer pushes code to the  <code class="language-plaintext highlighter-rouge">main</code>  branch in GitHub.</li>
    </ul>
  </li>
  <li>
    <p><strong>GitHub Actions CI</strong>:</p>

    <ul>
      <li>
        <p>GitHub Actions triggers a CI workflow:</p>

        <ul>
          <li>
            <p>Builds the application.</p>
          </li>
          <li>
            <p>Runs tests.</p>
          </li>
          <li>
            <p>Builds and pushes a Docker image to a container registry.</p>
          </li>
          <li>
            <p>Updates the Kubernetes manifests (e.g., Helm chart) in the Git repository with the new image tag.</p>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Argo CD CD</strong>:</p>

    <ul>
      <li>
        <p>Argo CD detects changes in the Git repository.</p>
      </li>
      <li>
        <p>It syncs the new application state to the Kubernetes cluster.</p>
      </li>
      <li>
        <p>The application is deployed to the desired environment (e.g., staging or production).</p>
      </li>
    </ul>
  </li>
</ol>

<p>Alright, now, let’s set up both for an example Kubernetes environment.</p>

<hr />

<h2 id="set-up-cicd-pipeline">Set up CI/CD Pipeline</h2>
<h3 id="step-1-set-up-your-kubernetes--argocd-environment">Step 1: Set Up Your Kubernetes &amp; ArgoCD Environment</h3>

<p>Before starting, ensure you have:</p>

<p>✅ <strong>A Kubernetes cluster (Minikube, Kind, EKS, GKE, AKS, etc.)</strong><br />
✅ <strong>ArgoCD installed in your cluster (<a href="https://shantoroy.com/kubernetes/kubernetes-deployment-with-argocd-gitops/">Day 34 Guide</a>)</strong><br />
✅ <strong>A GitHub repository with Kubernetes manifests</strong></p>

<hr />

<h3 id="step-2-create-a-github-actions-workflow-for-ci">Step 2: Create a GitHub Actions Workflow for CI</h3>

<h4 id="-create-githubworkflowsciyaml">** Create <code class="language-plaintext highlighter-rouge">.github/workflows/ci.yaml</code>**</h4>
<p>This <strong>CI pipeline</strong> will:</p>
<ul>
  <li>Build and tag a Docker image</li>
  <li>Push it to <strong>GitHub Container Registry (GHCR) or Docker Hub</strong></li>
</ul>

<p><strong><code class="language-plaintext highlighter-rouge">.github/workflows/ci.yaml</code></strong></p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">CI - Build &amp; Push Docker Image</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">main</span>
    <span class="na">paths</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">app/**"</span>  <span class="c1"># Only trigger when app code changes</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout code</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v3</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Log in to GitHub Container Registry</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">echo "$" | docker login ghcr.io -u $ --password-stdin</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Build Docker Image</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">docker build -t ghcr.io/$/myapp:$ -f app/Dockerfile .</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Push Image to GHCR</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">docker push ghcr.io/$/myapp:$</span>
</code></pre></div></div>

<p><strong>Set up GitHub Secrets</strong>:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">GHCR_PAT</code>: <strong>GitHub Container Registry Personal Access Token</strong></li>
  <li><code class="language-plaintext highlighter-rouge">DOCKERHUB_USERNAME</code>, <code class="language-plaintext highlighter-rouge">DOCKERHUB_PASSWORD</code>: (if using Docker Hub instead)</li>
</ul>

<hr />

<h3 id="step-3-automate-kubernetes-deployment-with-cd">Step 3: Automate Kubernetes Deployment with CD</h3>

<h4 id="-create-githubworkflowscdyaml">** Create <code class="language-plaintext highlighter-rouge">.github/workflows/cd.yaml</code>**</h4>

<p>This workflow:</p>

<ul>
  <li>Updates Kubernetes <strong>manifests</strong> with the new image tag</li>
  <li>Pushes changes to the <strong>GitOps repository</strong></li>
  <li>ArgoCD automatically syncs and deploys the new version</li>
</ul>

<p><strong><code class="language-plaintext highlighter-rouge">.github/workflows/cd.yaml</code></strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">CD - Deploy to Kubernetes via ArgoCD</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">workflow_run</span><span class="pi">:</span>
    <span class="na">workflows</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">CI</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">Build</span><span class="nv"> </span><span class="s">&amp;</span><span class="nv"> </span><span class="s">Push</span><span class="nv"> </span><span class="s">Docker</span><span class="nv"> </span><span class="s">Image"</span><span class="pi">]</span>
    <span class="na">types</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">completed</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">deploy</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout GitOps Repository</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">repository</span><span class="pi">:</span> <span class="s">&lt;your-gitops-repo&gt;</span>
          <span class="na">token</span><span class="pi">:</span> <span class="s">$</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Update Kubernetes Deployment YAML</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">sed -i "s|image: .*|image: ghcr.io/$/myapp:$|" k8s/deployment.yaml</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Commit and Push Changes</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">git config --global user.name "GitHub Actions"</span>
          <span class="s">git config --global user.email "actions@github.com"</span>
          <span class="s">git add k8s/deployment.yaml</span>
          <span class="s">git commit -m "Update deployment image to $"</span>
          <span class="s">git push</span>

</code></pre></div></div>

<p><strong>How It Works?</strong></p>

<ol>
  <li><strong>CI Workflow</strong> builds &amp; pushes the Docker image.</li>
  <li><strong>CD Workflow</strong> updates <code class="language-plaintext highlighter-rouge">deployment.yaml</code> with the new image tag.</li>
  <li><strong>ArgoCD auto-syncs the changes and deploys the updated version.</strong></li>
</ol>

<hr />

<h3 id="step-4-create-an-argocd-application-for-gitops">Step 4: Create an ArgoCD Application for GitOps</h3>

<p>ArgoCD watches your Git repository and applies changes automatically.</p>

<p><strong><code class="language-plaintext highlighter-rouge">argocd-application.yaml</code></strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">argoproj.io/v1alpha1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Application</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">myapp</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">argocd</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">project</span><span class="pi">:</span> <span class="s">default</span>
  <span class="na">source</span><span class="pi">:</span>
    <span class="na">repoURL</span><span class="pi">:</span> <span class="s">https://github.com/&lt;your-gitops-repo&gt;.git</span>
    <span class="na">targetRevision</span><span class="pi">:</span> <span class="s">main</span>
    <span class="na">path</span><span class="pi">:</span> <span class="s">k8s</span>
  <span class="na">destination</span><span class="pi">:</span>
    <span class="na">server</span><span class="pi">:</span> <span class="s">https://kubernetes.default.svc</span>
    <span class="na">namespace</span><span class="pi">:</span> <span class="s">default</span>
  <span class="na">syncPolicy</span><span class="pi">:</span>
    <span class="na">automated</span><span class="pi">:</span>
      <span class="na">prune</span><span class="pi">:</span> <span class="no">true</span>
      <span class="na">selfHeal</span><span class="pi">:</span> <span class="no">true</span>
</code></pre></div></div>

<p>Apply it:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> argocd-application.yaml
</code></pre></div></div>

<hr />

<h3 id="step-5-test-the-pipeline">Step 5: Test the Pipeline</h3>

<h4 id="1️⃣-make-a-code-change"><strong>1️⃣ Make a Code Change</strong></h4>

<p>Modify <code class="language-plaintext highlighter-rouge">app/main.py</code> and push changes to <code class="language-plaintext highlighter-rouge">main</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git commit <span class="nt">-am</span> <span class="s2">"Update application logic"</span> git push origin main
</code></pre></div></div>

<h4 id="2️⃣-observe-cicd-pipeline"><strong>2️⃣ Observe CI/CD Pipeline</strong></h4>

<ul>
  <li>GitHub Actions runs the <strong>CI workflow</strong> → Builds &amp; pushes Docker image</li>
  <li>GitHub Actions runs the <strong>CD workflow</strong> → Updates <code class="language-plaintext highlighter-rouge">deployment.yaml</code></li>
  <li>ArgoCD <strong>auto-syncs &amp; deploys</strong> the updated application</li>
</ul>

<h4 id="3️⃣-verify-deployment"><strong>3️⃣ Verify Deployment</strong></h4>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get pods
kubectl get svc
</code></pre></div></div>

<p>Check your <strong>ArgoCD UI</strong> → The new version is deployed automatically!</p>

<hr />

<h2 id="final-thoughts">Final Thoughts</h2>

<p><strong>Key Takeaways</strong><br />
✅ <strong>CI/CD with GitHub Actions + ArgoCD enables fully automated Kubernetes deployments</strong><br />
✅ <strong>GitOps approach ensures consistency, security, and easy rollbacks</strong><br />
✅ <strong>ArgoCD eliminates manual <code class="language-plaintext highlighter-rouge">kubectl apply</code> commands</strong><br />
✅ <strong>Scalable CI/CD for cloud-native applications</strong></p>

<p><strong>Alternatives</strong>
While GitHub Actions and Argo CD are a great combination, here are some alternatives:</p>

<ul>
  <li>
    <p><strong>Jenkins + Argo CD</strong>: Use Jenkins for CI and Argo CD for CD.</p>
  </li>
  <li>
    <p><strong>GitLab CI/CD + Argo CD</strong>: Use GitLab CI/CD for CI and Argo CD for CD.</p>
  </li>
  <li>
    <p><strong>Tekton + Argo CD</strong>: Use Tekton for CI and Argo CD for CD.</p>
  </li>
</ul>

<p>Combining <strong>GitHub Actions</strong> for CI and <strong>Argo CD</strong> for CD is a proper choice for Kubernetes-based CI/CD pipelines. It provides a seamless, automated, and GitOps-driven workflow that ensures consistency, scalability, and visibility. This combination is particularly well-suited for teams already using GitHub and looking to adopt modern DevOps practices.</p>

<p><strong>What’s Next?</strong><br />
🔹 <strong>Day 36</strong>: Kubernetes Helm Charts 
🔹 <strong>Day 37</strong>: Kubernetes Deployment using Terraform
<!--stackedit_data:
eyJoaXN0b3J5IjpbLTE0NDczNzQ1MjksMTUwOTM0NTg1OV19
--></p>]]></content><author><name>Shanto Roy</name></author><category term="Kubernetes" /><category term="Kubernetes" /><category term="DevOps" /><category term="CI/CD" /><category term="GitHub Actions" /><category term="ArgoCD" /><category term="GitOps" /><category term="SRE" /><summary type="html"><![CDATA[Learn how to set up a CI/CD pipeline for Kubernetes using GitHub Actions and ArgoCD to automate deployments.]]></summary></entry><entry><title type="html">#100DaysOfSRE (Day 34): Automating Kubernetes Deployments with ArgoCD &amp;amp; GitOps</title><link href="https://shantoroy.com/kubernetes/kubernetes-deployment-with-argocd-gitops/" rel="alternate" type="text/html" title="#100DaysOfSRE (Day 34): Automating Kubernetes Deployments with ArgoCD &amp;amp; GitOps" /><published>2025-03-14T00:00:00+00:00</published><updated>2025-03-14T00:00:00+00:00</updated><id>https://shantoroy.com/kubernetes/kubernetes-deployment-with-argocd-gitops</id><content type="html" xml:base="https://shantoroy.com/kubernetes/kubernetes-deployment-with-argocd-gitops/"><![CDATA[<p><strong>Argo CD</strong>  is a popular GitOps tool for managing Kubernetes applications. It provides a declarative way to deploy and manage applications using Git as the single source of truth. Here are the key reasons why Argo CD is widely used:</p>

<hr />

<h4 id="1--gitops-principles">1.  <strong>GitOps Principles</strong></h4>

<ul>
  <li>
    <p><strong>Declarative Configuration</strong>: Argo CD uses YAML manifests stored in Git repositories to define the desired state of applications.</p>
  </li>
  <li>
    <p><strong>Version Control</strong>: All changes are tracked in Git, providing a clear audit trail and enabling rollbacks.</p>
  </li>
  <li>
    <p><strong>Automation</strong>: Argo CD continuously monitors the Git repository and automatically syncs the cluster state with the desired state.</p>
  </li>
</ul>

<h4 id="2--continuous-delivery">2.  <strong>Continuous Delivery</strong></h4>

<ul>
  <li>
    <p>Argo CD ensures that the Kubernetes cluster is always in sync with the desired state defined in Git.</p>
  </li>
  <li>
    <p>It supports automated deployments, reducing manual intervention and human error.</p>
  </li>
</ul>

<h4 id="3--multi-environment-support">3.  <strong>Multi-Environment Support</strong></h4>

<ul>
  <li>Argo CD can manage applications across multiple environments (e.g., dev, staging, production) using the same Git repository.</li>
</ul>

<h4 id="4--self-healing">4.  <strong>Self-Healing</strong></h4>

<ul>
  <li>If the cluster state drifts from the desired state (e.g., due to manual changes), Argo CD can automatically correct it.</li>
</ul>

<h4 id="5--user-interface">5.  <strong>User Interface</strong></h4>

<ul>
  <li>Argo CD provides a web-based UI for visualizing applications, their status, and synchronization state.</li>
</ul>

<h4 id="6--integration-with-kubernetes-ecosystem">6.  <strong>Integration with Kubernetes Ecosystem</strong></h4>

<ul>
  <li>
    <p>Argo CD integrates seamlessly with Helm, Kustomize, and other Kubernetes tools.</p>
  </li>
  <li>
    <p>It supports multi-cluster deployments and can manage applications across multiple Kubernetes clusters.</p>
  </li>
</ul>

<p>Today, we’ll <strong>set up ArgoCD, deploy an app using GitOps, and automate Kubernetes deployments.</strong></p>

<hr />

<h2 id="step-1-install-argocd-in-kubernetes">Step 1: Install ArgoCD in Kubernetes</h2>

<p>Deploy ArgoCD in the <code class="language-plaintext highlighter-rouge">argocd</code> namespace:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl create namespace argocd
kubectl apply <span class="nt">-n</span> argocd <span class="nt">-f</span> https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
</code></pre></div></div>

<p>Wait for the pods to be ready:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get pods <span class="nt">-n</span> argocd
</code></pre></div></div>

<p>Expose the ArgoCD UI:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl port-forward svc/argocd-server <span class="nt">-n</span> argocd 8080:443
</code></pre></div></div>

<p>Now, access <strong>ArgoCD UI at</strong>: https://localhost:8080</p>

<hr />

<h2 id="step-2-login--change-argocd-admin-password">Step 2: Login &amp; Change ArgoCD Admin Password</h2>

<p>Fetch the <strong>default admin password</strong>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get secret argocd-initial-admin-secret <span class="nt">-n</span> argocd <span class="nt">-o</span> <span class="nv">jsonpath</span><span class="o">=</span><span class="s2">"{.data.password}"</span> | <span class="nb">base64</span> <span class="nt">-d</span>
</code></pre></div></div>

<p>Login to ArgoCD CLI:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>argocd login localhost:8080 <span class="nt">--username</span> admin <span class="nt">--password</span> &lt;your-password&gt;
</code></pre></div></div>

<p>Change the password:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>argocd account update-password
</code></pre></div></div>

<hr />

<h2 id="step-3-deploy-an-app-using-gitops">Step 3: Deploy an App Using GitOps</h2>

<h3 id="1️⃣-prepare-the-git-repository">1️⃣ <strong>Prepare the Git Repository</strong></h3>

<p>Create a <strong>GitHub repository</strong> (e.g., <code class="language-plaintext highlighter-rouge">k8s-gitops-demo</code>) with the following structure:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>k8s-gitops-demo/
├── manifests/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── ingress.yaml
└── .gitignore
</code></pre></div></div>

<h3 id="2️⃣-define-kubernetes-manifests">2️⃣ <strong>Define Kubernetes Manifests</strong></h3>

<p><strong>manifests/deployment.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">2</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">myapp</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">myapp</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">myapp</span>
        <span class="na">image</span><span class="pi">:</span> <span class="s">nginx:latest</span>
        <span class="na">ports</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">80</span>
</code></pre></div></div>

<p><strong>manifests/service.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">myapp-service</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> <span class="s">myapp</span>
  <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>
      <span class="na">port</span><span class="pi">:</span> <span class="m">80</span>
      <span class="na">targetPort</span><span class="pi">:</span> <span class="m">80</span>
</code></pre></div></div>

<h3 id="3️⃣-push-code-to-git">3️⃣ <strong>Push Code to Git</strong></h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git init
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"Initial Kubernetes manifests"</span> git branch <span class="nt">-M</span> main
git remote add origin https://github.com/&lt;your-username&gt;/k8s-gitops-demo.git
git push <span class="nt">-u</span> origin main
</code></pre></div></div>

<hr />

<h2 id="step-4-create-an-argocd-application">Step 4: Create an ArgoCD Application</h2>

<p>Create an ArgoCD <strong>Application</strong> that syncs with your Git repository.</p>

<p><strong>argocd-application.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">argoproj.io/v1alpha1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Application</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">myapp</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">argocd</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">project</span><span class="pi">:</span> <span class="s">default</span>
  <span class="na">source</span><span class="pi">:</span>
    <span class="na">repoURL</span><span class="pi">:</span> <span class="s">https://github.com/&lt;your-username&gt;/k8s-gitops-demo.git</span>
    <span class="na">targetRevision</span><span class="pi">:</span> <span class="s">main</span>
    <span class="na">path</span><span class="pi">:</span> <span class="s">manifests</span>
  <span class="na">destination</span><span class="pi">:</span>
    <span class="na">server</span><span class="pi">:</span> <span class="s">https://kubernetes.default.svc</span>
    <span class="na">namespace</span><span class="pi">:</span> <span class="s">default</span>
  <span class="na">syncPolicy</span><span class="pi">:</span>
    <span class="na">automated</span><span class="pi">:</span>
      <span class="na">prune</span><span class="pi">:</span> <span class="no">true</span>
      <span class="na">selfHeal</span><span class="pi">:</span> <span class="no">true</span>
</code></pre></div></div>

<p>Apply it:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> argocd-application.yaml
</code></pre></div></div>

<p>Check the app status:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>argocd app list
</code></pre></div></div>

<p>Verify deployment:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get pods
kubectl get svc
</code></pre></div></div>

<hr />

<h2 id="step-5-automate-deployments-with-gitops">Step 5: Automate Deployments with GitOps</h2>

<p>1️⃣ <strong>Make a Change in Git</strong><br />
Modify <code class="language-plaintext highlighter-rouge">deployment.yaml</code> to use a different image (e.g., <code class="language-plaintext highlighter-rouge">nginx:1.23</code>).<br />
Commit &amp; push the change:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git commit <span class="nt">-am</span> <span class="s2">"Updated image version"</span> git push origin main
</code></pre></div></div>

<p>2️⃣ <strong>ArgoCD Auto-Syncs Changes</strong><br />
Check the ArgoCD UI—your deployment will <strong>automatically update!</strong></p>

<hr />

<h2 id="step-6-rollback-with-argocd">Step 6: Rollback with ArgoCD</h2>

<p>If a deployment breaks, rollback easily:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>argocd app <span class="nb">history </span>myapp
argocd app rollback myapp 2
</code></pre></div></div>

<p>Now, the app is restored to version <code class="language-plaintext highlighter-rouge">2</code>.</p>

<hr />

<h2 id="remarks">Remarks</h2>

<p><strong>Key Takeaways</strong><br />
✅ <strong>ArgoCD automates Kubernetes deployments using Git</strong><br />
✅ <strong>GitOps ensures consistency, auditability, and automation</strong><br />
✅ <strong>Auto-sync eliminates manual <code class="language-plaintext highlighter-rouge">kubectl apply</code> commands</strong><br />
✅ <strong>Rollback instantly using ArgoCD commands</strong></p>

<p>While GitHub Actions and Argo CD are a great combination, here are some alternatives:</p>

<ul>
  <li>
    <p><strong>Jenkins + Argo CD</strong>: Use Jenkins for CI and Argo CD for CD.</p>
  </li>
  <li>
    <p><strong>GitLab CI/CD + Argo CD</strong>: Use GitLab CI/CD for CI and Argo CD for CD.</p>
  </li>
  <li>
    <p><strong>Tekton + Argo CD</strong>: Use Tekton for CI and Argo CD for CD.</p>
  </li>
</ul>

<p><strong>What’s Next?</strong><br />
🔹 <strong>Day 35</strong>: Kubernetes CI/CD Pipeline with GitHub Actions &amp; ArgoCD<br />
🔹 <strong>Day 36</strong>: Securing Kubernetes Workloads with Network Policies
<!--stackedit_data:
eyJoaXN0b3J5IjpbNzEyMjYyOTk0LC0xMjA3NjU1NzM0XX0=
--></p>]]></content><author><name>Shanto Roy</name></author><category term="Kubernetes" /><category term="Kubernetes" /><category term="DevOps" /><category term="ArgoCD" /><category term="GitOps" /><category term="CI/CD" /><category term="SRE" /><summary type="html"><![CDATA[Learn how to automate Kubernetes deployments using ArgoCD and GitOps principles for continuous delivery.]]></summary></entry><entry><title type="html">#100DaysOfSRE (Day 33): Monitoring Kubernetes Apps with Prometheus &amp;amp; Grafana</title><link href="https://shantoroy.com/kubernetes/kubernetes-monitoring-with-grafana-prometheus/" rel="alternate" type="text/html" title="#100DaysOfSRE (Day 33): Monitoring Kubernetes Apps with Prometheus &amp;amp; Grafana" /><published>2025-03-13T00:00:00+00:00</published><updated>2025-03-13T00:00:00+00:00</updated><id>https://shantoroy.com/kubernetes/kubernetes-monitoring-with-grafana-prometheus</id><content type="html" xml:base="https://shantoroy.com/kubernetes/kubernetes-monitoring-with-grafana-prometheus/"><![CDATA[<p><strong>Why Monitor Kubernetes?</strong></p>
<ul>
  <li><strong>Detect performance bottlenecks</strong> before they impact users</li>
  <li><strong>Visualize metrics</strong> such as CPU, memory, and request rates</li>
  <li><strong>Set up alerts</strong> for failures or resource exhaustion</li>
  <li><strong>Improve system reliability</strong> and proactively respond to issues</li>
</ul>

<p>Today, we’ll <strong>install, configure, and visualize Kubernetes metrics</strong> using <strong>Prometheus &amp; Grafana</strong> on Minikube.</p>

<hr />

<h2 id="step-1-enable-monitoring-addons-in-minikube">Step 1: Enable Monitoring Addons in Minikube</h2>

<p>Minikube provides a <strong>built-in Prometheus-Grafana stack</strong>. To enable it:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minikube addons <span class="nb">enable </span>metrics-server
minikube addons <span class="nb">enable </span>prometheus
minikube addons <span class="nb">enable </span>grafana
</code></pre></div></div>

<p>Check running pods:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get pods <span class="nt">-n</span> monitoring
</code></pre></div></div>

<hr />

<h2 id="step-2-access-prometheus--grafana">Step 2: Access Prometheus &amp; Grafana</h2>

<h3 id="access-prometheus-dashboard"><strong>Access Prometheus Dashboard</strong></h3>

<p>Forward the Prometheus service to your local machine:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl port-forward <span class="nt">-n</span> monitoring svc/prometheus-k8s 9090:9090
</code></pre></div></div>

<p>Now, open <strong>http://localhost:9090</strong> in your browser.</p>

<h3 id="access-grafana-dashboard"><strong>Access Grafana Dashboard</strong></h3>

<p>Forward Grafana service:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl port-forward <span class="nt">-n</span> monitoring svc/grafana 3000:3000
</code></pre></div></div>

<p>Now, open <strong>http://localhost:3000</strong><br />
(Default login: <strong>admin / prom-operator</strong>)</p>

<hr />

<h2 id="step-3-configure-prometheus-to-collect-metrics">Step 3: Configure Prometheus to Collect Metrics</h2>

<p>Prometheus scrapes metrics from Kubernetes using <strong>ServiceMonitors</strong>. Let’s define one.</p>

<p><strong>prometheus-servicemonitor.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">monitoring.coreos.com/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">ServiceMonitor</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">myapp-monitor</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">backend</span>
  <span class="na">endpoints</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">port</span><span class="pi">:</span> <span class="s">http</span>
    <span class="na">interval</span><span class="pi">:</span> <span class="s">15s</span>
</code></pre></div></div>

<p>Apply it:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> prometheus-servicemonitor.yaml
</code></pre></div></div>

<p>Now, Prometheus will <strong>scrape metrics</strong> every <strong>15 seconds</strong> from the <strong>backend service</strong>.</p>

<hr />

<h2 id="step-4-expose-application-metrics">Step 4: Expose Application Metrics</h2>

<p>By default, Prometheus expects an endpoint like <strong>/metrics</strong> to collect data. Let’s modify our <strong>backend</strong> to expose metrics.</p>

<p><strong>backend/app.py</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>
<span class="kn">from</span> <span class="nn">prometheus_client</span> <span class="kn">import</span> <span class="n">start_http_server</span><span class="p">,</span> <span class="n">Counter</span>

<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
<span class="n">REQUESTS</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">(</span><span class="s">'http_requests_total'</span><span class="p">,</span> <span class="s">'Total number of HTTP requests'</span><span class="p">)</span>

<span class="o">@</span><span class="n">app</span><span class="p">.</span><span class="n">route</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">home</span><span class="p">():</span>
    <span class="n">REQUESTS</span><span class="p">.</span><span class="n">inc</span><span class="p">()</span>
    <span class="k">return</span> <span class="s">"Hello, Kubernetes Monitoring!"</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">start_http_server</span><span class="p">(</span><span class="mi">8000</span><span class="p">)</span>  <span class="c1"># Expose metrics on /metrics
</span>    <span class="n">app</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">"0.0.0.0"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">5000</span><span class="p">)</span>
</code></pre></div></div>

<p>Rebuild and restart the backend:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> my-backend <span class="nb">.</span>
kubectl rollout restart deployment backend
</code></pre></div></div>

<p>Verify metrics:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl http://backend:8000/metrics
</code></pre></div></div>

<hr />

<h2 id="step-5-visualize-metrics-in-grafana">Step 5: Visualize Metrics in Grafana</h2>

<h3 id="import-prometheus-as-a-data-source"><strong>Import Prometheus as a Data Source</strong></h3>

<ol>
  <li>Open <strong>Grafana</strong> (<code class="language-plaintext highlighter-rouge">http://localhost:3000</code>)</li>
  <li>Go to <strong>Configuration &gt; Data Sources &gt; Add Data Source</strong></li>
  <li>Select <strong>Prometheus</strong></li>
  <li>Enter <strong>http://prometheus-k8s.monitoring.svc:9090</strong> as the URL</li>
  <li>Click <strong>Save &amp; Test</strong></li>
</ol>

<h3 id="import-a-prebuilt-dashboard"><strong>Import a Prebuilt Dashboard</strong></h3>

<ol>
  <li>Go to <strong>Dashboards &gt; Import</strong></li>
  <li>Use <strong>ID: 3119 (Kubernetes Cluster Monitoring)</strong></li>
  <li>Click <strong>Load</strong> and <strong>Import</strong></li>
</ol>

<p>Now we can see real-time Kubernetes metrics!</p>

<p>Please, note that Grafana provides a variety of <strong>prebuilt dashboard templates</strong> that you can import and use directly. These templates are often available in the <a href="https://grafana.com/grafana/dashboards/">Grafana Dashboards library</a> or shared by the community.</p>

<p>Some other example dashboards for Kubernetes are:</p>
<ul>
  <li>
    <p><a href="https://grafana.com/grafana/dashboards/315">Kubernetes Cluster Monitoring</a>  - ID:  <code class="language-plaintext highlighter-rouge">315</code></p>
  </li>
  <li>
    <p><a href="https://grafana.com/grafana/dashboards/6417">Kubernetes Node Monitoring</a>  - ID:  <code class="language-plaintext highlighter-rouge">6417</code></p>
  </li>
</ul>

<hr />

<h2 id="step-6-set-up-alerts-with-prometheus-alertmanager">Step 6: Set Up Alerts with Prometheus Alertmanager</h2>

<p>Well, now, let’s define an <strong>Alert Rule</strong>:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># alert-rules.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">monitoring.coreos.com/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">PrometheusRule</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">high-cpu-alert</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">monitoring</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">groups</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">instance-rules</span>
    <span class="na">rules</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">alert</span><span class="pi">:</span> <span class="s">HighCPUUsage</span>
      <span class="na">expr</span><span class="pi">:</span> <span class="s">rate(container_cpu_usage_seconds_total[2m]) &gt; </span><span class="m">0.5</span>
      <span class="na">for</span><span class="pi">:</span> <span class="s">2m</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">severity</span><span class="pi">:</span> <span class="s">critical</span>
      <span class="na">annotations</span><span class="pi">:</span>
        <span class="na">summary</span><span class="pi">:</span> <span class="s2">"</span><span class="s">High</span><span class="nv"> </span><span class="s">CPU</span><span class="nv"> </span><span class="s">Usage</span><span class="nv"> </span><span class="s">Detected"</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">CPU</span><span class="nv"> </span><span class="s">usage</span><span class="nv"> </span><span class="s">is</span><span class="nv"> </span><span class="s">above</span><span class="nv"> </span><span class="s">50%</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">more</span><span class="nv"> </span><span class="s">than</span><span class="nv"> </span><span class="s">2</span><span class="nv"> </span><span class="s">minutes."</span>
</code></pre></div></div>

<p>Apply it:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> alert-rules.yaml
</code></pre></div></div>

<p>Prometheus will now trigger an <strong>alert</strong> if <strong>CPU usage exceeds 50%</strong> for <strong>2 minutes</strong>.</p>

<hr />

<h2 id="remarks">Remarks</h2>

<p><strong>Key Takeaways</strong><br />
✅ <strong>Prometheus collects metrics</strong> from Kubernetes workloads<br />
✅ <strong>Grafana visualizes metrics</strong> in real-time dashboards<br />
✅ <strong>ServiceMonitors configure scraping rules</strong> for Prometheus<br />
✅ <strong>Alerts notify teams</strong> when performance degrades</p>

<p><strong>What’s Next?</strong><br />
🔹 <strong>Day 34</strong>: Automating Kubernetes Deployments with ArgoCD &amp; GitOps<br />
🔹 <strong>Day 35</strong>: Building a Kubernetes CI/CD Pipeline</p>

<!--stackedit_data:
eyJoaXN0b3J5IjpbLTEzODc4NTg1ODIsLTQyNTA1ODk2XX0=
-->]]></content><author><name>Shanto Roy</name></author><category term="Kubernetes" /><category term="Kubernetes" /><category term="Monitoring" /><category term="Prometheus" /><category term="Grafana" /><category term="Observability" /><category term="SRE" /><summary type="html"><![CDATA[Learn how to set up Prometheus and Grafana for monitoring Kubernetes applications, collecting metrics, and visualizing real-time performance.]]></summary></entry><entry><title type="html">#100DaysOfSRE (Day 32): Advanced Kubernetes: Ingress, ConfigMaps, Secrets &amp;amp; Helm</title><link href="https://shantoroy.com/kubernetes/advanced-kubernetes-ingress-configmap-helm/" rel="alternate" type="text/html" title="#100DaysOfSRE (Day 32): Advanced Kubernetes: Ingress, ConfigMaps, Secrets &amp;amp; Helm" /><published>2025-03-12T00:00:00+00:00</published><updated>2025-03-12T00:00:00+00:00</updated><id>https://shantoroy.com/kubernetes/advanced-kubernetes-ingress-configmap-helm</id><content type="html" xml:base="https://shantoroy.com/kubernetes/advanced-kubernetes-ingress-configmap-helm/"><![CDATA[<p>In <strong>Day 31</strong>, we deployed a <strong>Python-based backend, frontend, and PostgreSQL database</strong> on Minikube using Kubernetes manifests. Now, let’s <strong>enhance</strong> our setup by adding:</p>

<p>✅ <strong>Ingress Controller</strong> for external access<br />
✅ <strong>ConfigMaps &amp; Secrets</strong> for secure configuration<br />
✅ <strong>Helm Charts</strong> for easier deployment management</p>

<hr />

<h2 id="step-1-add-an-ingress-controller-for-external-access">Step 1: Add an Ingress Controller for External Access</h2>

<p>By default, Kubernetes services are <strong>only accessible inside the cluster</strong>. Instead of using <code class="language-plaintext highlighter-rouge">NodePort</code>, we will configure an <strong>Ingress Controller</strong> to route requests.</p>

<h3 id="install-ingress-controller-on-minikube"><strong>Install Ingress Controller on Minikube</strong></h3>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minikube addons <span class="nb">enable </span>ingress
</code></pre></div></div>

<h3 id="define-an-ingress-resource"><strong>Define an Ingress Resource</strong></h3>

<p><strong>ingress.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">networking.k8s.io/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Ingress</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">myapp-ingress</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
  <span class="na">annotations</span><span class="pi">:</span>
    <span class="na">nginx.ingress.kubernetes.io/rewrite-target</span><span class="pi">:</span> <span class="s">/</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">rules</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">host</span><span class="pi">:</span> <span class="s">myapp.local</span>
    <span class="na">http</span><span class="pi">:</span>
      <span class="na">paths</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">path</span><span class="pi">:</span> <span class="s">/backend</span>
        <span class="na">pathType</span><span class="pi">:</span> <span class="s">Prefix</span>
        <span class="na">backend</span><span class="pi">:</span>
          <span class="na">service</span><span class="pi">:</span>
            <span class="na">name</span><span class="pi">:</span> <span class="s">backend</span>
            <span class="na">port</span><span class="pi">:</span>
              <span class="na">number</span><span class="pi">:</span> <span class="m">5000</span>
      <span class="pi">-</span> <span class="na">path</span><span class="pi">:</span> <span class="s">/</span>
        <span class="na">pathType</span><span class="pi">:</span> <span class="s">Prefix</span>
        <span class="na">backend</span><span class="pi">:</span>
          <span class="na">service</span><span class="pi">:</span>
            <span class="na">name</span><span class="pi">:</span> <span class="s">frontend</span>
            <span class="na">port</span><span class="pi">:</span>
              <span class="na">number</span><span class="pi">:</span> <span class="m">3000</span>
</code></pre></div></div>

<h3 id="apply-the-ingress-configuration"><strong>Apply the Ingress Configuration</strong></h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> ingress.yaml
</code></pre></div></div>

<h3 id="test-the-ingress"><strong>Test the Ingress</strong></h3>

<p>Update <code class="language-plaintext highlighter-rouge">/etc/hosts</code> (Linux/macOS) to map <code class="language-plaintext highlighter-rouge">myapp.local</code> to Minikube’s IP:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span>  <span class="s2">"</span><span class="si">$(</span>minikube ip<span class="si">)</span><span class="s2"> myapp.local"</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/hosts
</code></pre></div></div>

<p>Now, visit <strong>http://myapp.local/</strong> for the frontend and <strong>http://myapp.local/backend</strong> for the backend!</p>

<hr />

<h2 id="step-2-use-configmaps--secrets-for-secure-configuration">Step 2: Use ConfigMaps &amp; Secrets for Secure Configuration</h2>

<p>Instead of <strong>hardcoding</strong> environment variables, we will use <strong>ConfigMaps</strong> and <strong>Secrets</strong>.</p>

<h3 id="create-a-configmap-for-database-url"><strong>Create a ConfigMap for Database URL</strong></h3>

<p><strong>configmap.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">ConfigMap</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">app-config</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">data</span><span class="pi">:</span>
  <span class="na">DATABASE_URL</span><span class="pi">:</span> <span class="s2">"</span><span class="s">postgresql://user:password@postgres:5432/mydatabase"</span>
</code></pre></div></div>

<h3 id="create-a-secret-for-database-credentials"><strong>Create a Secret for Database Credentials</strong></h3>

<p><strong>secret.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Secret</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">db-secret</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">type</span><span class="pi">:</span> <span class="s">Opaque</span>
<span class="na">data</span><span class="pi">:</span>
  <span class="na">POSTGRES_USER</span><span class="pi">:</span> <span class="s">dXNlcg==</span>  <span class="c1"># Base64 encoded 'user'</span>
  <span class="na">POSTGRES_PASSWORD</span><span class="pi">:</span> <span class="s">cGFzc3dvcmQ=</span>  <span class="c1"># Base64 encoded 'password'</span>
</code></pre></div></div>

<h3 id="modify-backend-deployment-to-use-configmap--secret"><strong>Modify Backend Deployment to Use ConfigMap &amp; Secret</strong></h3>

<p><strong>backend-deployment.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">backend</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">1</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">backend</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">backend</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">backend</span>
        <span class="na">image</span><span class="pi">:</span> <span class="s">python:3.10</span>
        <span class="na">env</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">DATABASE_URL</span>
          <span class="na">valueFrom</span><span class="pi">:</span>
            <span class="na">configMapKeyRef</span><span class="pi">:</span>
              <span class="na">name</span><span class="pi">:</span> <span class="s">app-config</span>
              <span class="na">key</span><span class="pi">:</span> <span class="s">DATABASE_URL</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">POSTGRES_USER</span>
          <span class="na">valueFrom</span><span class="pi">:</span>
            <span class="na">secretKeyRef</span><span class="pi">:</span>
              <span class="na">name</span><span class="pi">:</span> <span class="s">db-secret</span>
              <span class="na">key</span><span class="pi">:</span> <span class="s">POSTGRES_USER</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">POSTGRES_PASSWORD</span>
          <span class="na">valueFrom</span><span class="pi">:</span>
            <span class="na">secretKeyRef</span><span class="pi">:</span>
              <span class="na">name</span><span class="pi">:</span> <span class="s">db-secret</span>
              <span class="na">key</span><span class="pi">:</span> <span class="s">POSTGRES_PASSWORD</span>
        <span class="na">ports</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">5000</span>
</code></pre></div></div>

<h3 id="apply-configmaps--secrets"><strong>Apply ConfigMaps &amp; Secrets</strong></h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> configmap.yaml
kubectl apply <span class="nt">-f</span> secret.yaml
kubectl apply <span class="nt">-f</span> backend-deployment.yaml
</code></pre></div></div>

<hr />

<h2 id="step-3-use-helm-charts-for-deployment-management">Step 3: Use Helm Charts for Deployment Management</h2>

<p>Manually managing Kubernetes YAML files is <strong>tedious</strong>. Instead, we can use <strong>Helm</strong>, the package manager for Kubernetes.</p>

<h3 id="install-helm"><strong>Install Helm</strong></h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>helm <span class="c"># macOS </span>
choco <span class="nb">install </span>kubernetes-helm <span class="c"># Windows</span>
</code></pre></div></div>

<h3 id="create-a-helm-chart"><strong>Create a Helm Chart</strong></h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm create myapp-chart
</code></pre></div></div>

<h3 id="modify-helm-chart-to-deploy-the-app"><strong>Modify Helm Chart to Deploy the App</strong></h3>

<p>Inside <code class="language-plaintext highlighter-rouge">myapp-chart/values.yaml</code>, update the service and deployment values.</p>

<p><strong>myapp-chart/values.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">backend</span><span class="pi">:</span>
  <span class="na">image</span><span class="pi">:</span> <span class="s">python:3.10</span>
  <span class="na">service</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">ClusterIP</span>
    <span class="na">port</span><span class="pi">:</span> <span class="m">5000</span>

<span class="na">frontend</span><span class="pi">:</span>
  <span class="na">image</span><span class="pi">:</span> <span class="s">node:18</span>
  <span class="na">service</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">ClusterIP</span>
    <span class="na">port</span><span class="pi">:</span> <span class="m">3000</span>

<span class="na">database</span><span class="pi">:</span>
  <span class="na">image</span><span class="pi">:</span> <span class="s">postgres:15</span>
  <span class="na">service</span><span class="pi">:</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">ClusterIP</span>
    <span class="na">port</span><span class="pi">:</span> <span class="m">5432</span>
  <span class="na">env</span><span class="pi">:</span>
    <span class="na">POSTGRES_USER</span><span class="pi">:</span> <span class="s">user</span>
    <span class="na">POSTGRES_PASSWORD</span><span class="pi">:</span> <span class="s">password</span>
    <span class="na">POSTGRES_DB</span><span class="pi">:</span> <span class="s">mydatabase</span>
</code></pre></div></div>

<h3 id="deploy-the-application-using-helm"><strong>Deploy the Application using Helm</strong></h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm <span class="nb">install </span>myapp ./myapp-chart
</code></pre></div></div>

<h3 id="check-the-helm-deployment"><strong>Check the Helm Deployment</strong></h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm list
kubectl get pods <span class="nt">-n</span> myapp
</code></pre></div></div>

<h3 id="upgrade-the-helm-release"><strong>Upgrade the Helm Release</strong></h3>

<p>If you modify the configuration:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm upgrade myapp ./myapp-chart
</code></pre></div></div>

<h3 id="uninstall-the-helm-release"><strong>Uninstall the Helm Release</strong></h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm uninstall myapp
</code></pre></div></div>

<hr />

<h2 id="final-thoughts">Final Thoughts</h2>

<p><strong>Key Takeaways</strong><br />
✅ <strong>Ingress Controllers</strong> expose applications externally with routing rules<br />
✅ <strong>ConfigMaps &amp; Secrets</strong> store environment variables securely<br />
✅ <strong>Helm</strong> simplifies Kubernetes deployments with reusable charts</p>

<p><strong>What’s Next?</strong><br />
🔹 <strong>Day 33</strong>: Monitoring Kubernetes Apps with Prometheus &amp; Grafana<br />
🔹 <strong>Day 34</strong>: CI/CD Pipelines for Kubernetes Deployments</p>

<p><strong>Stay tuned for more Kubernetes posts in the #100DaysOfSRE series!</strong></p>

<!--stackedit_data:
eyJoaXN0b3J5IjpbLTEwMTgxNDg4NzgsLTE4MDAyNzIzMl19
-->]]></content><author><name>Shanto Roy</name></author><category term="Kubernetes" /><category term="Kubernetes" /><category term="Ingress" /><category term="ConfigMaps" /><category term="Secrets" /><category term="Helm" /><category term="SRE" /><summary type="html"><![CDATA[Take your Kubernetes skills to the next level by adding Ingress for routing, ConfigMaps & Secrets for secure configuration, and Helm Charts for deployment.]]></summary></entry><entry><title type="html">#100DaysOfSRE (Day 31): How to Write Kubernetes Manifest Files: Kubernetes vs Docker-Compose</title><link href="https://shantoroy.com/kubernetes/how-to-write-kubernetes-manifest-files/" rel="alternate" type="text/html" title="#100DaysOfSRE (Day 31): How to Write Kubernetes Manifest Files: Kubernetes vs Docker-Compose" /><published>2025-03-11T00:00:00+00:00</published><updated>2025-03-11T00:00:00+00:00</updated><id>https://shantoroy.com/kubernetes/how-to-write-kubernetes-manifest-files</id><content type="html" xml:base="https://shantoroy.com/kubernetes/how-to-write-kubernetes-manifest-files/"><![CDATA[<p>Many developers start their containerized applications using <strong>Docker-Compose</strong>, but for <strong>scalability and production readiness</strong>, Kubernetes is the better choice. In this tutorial, we will:</p>

<p>✅ Define a <strong>Docker-Compose setup</strong> with a Python <strong>backend, frontend, and PostgreSQL</strong><br />
✅ Convert it into <strong>Kubernetes manifests</strong> (YAML files)<br />
✅ Deploy the <strong>Kubernetes setup on Minikube</strong></p>

<hr />

<h2 id="docker-compose-setup">Docker-Compose Setup</h2>
<p>Well, in my previous posts, we have already seen how to set up docker-compose to deploy a full-stack service. Let’s revise that first before we start learning how to write kubernetes manifest files.</p>

<p>Here’s how we can define our <strong>docker-compose.yml</strong> for a simple Python backend, frontend, and a PostgreSQL database.</p>

<h3 id="docker-composeyml"><strong>docker-compose.yml</strong></h3>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="s2">"</span><span class="s">3.8"</span>

<span class="na">services</span><span class="pi">:</span>
  <span class="na">db</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">postgres:15</span>
    <span class="na">container_name</span><span class="pi">:</span> <span class="s">postgres_db</span>
    <span class="na">restart</span><span class="pi">:</span> <span class="s">always</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="na">POSTGRES_USER</span><span class="pi">:</span> <span class="s">user</span>
      <span class="na">POSTGRES_PASSWORD</span><span class="pi">:</span> <span class="s">password</span>
      <span class="na">POSTGRES_DB</span><span class="pi">:</span> <span class="s">mydatabase</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">5432:5432"</span>

  <span class="na">backend</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">python:3.10</span>
    <span class="na">container_name</span><span class="pi">:</span> <span class="s">backend</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">db</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="na">DATABASE_URL</span><span class="pi">:</span> <span class="s">postgresql://user:password@db:5432/mydatabase</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">5000:5000"</span>
    <span class="na">command</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">python"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">-m"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">http.server"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">5000"</span><span class="pi">]</span>

  <span class="na">frontend</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">node:18</span>
    <span class="na">container_name</span><span class="pi">:</span> <span class="s">frontend</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">backend</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">3000:3000"</span>
    <span class="na">command</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">npx"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">http-server"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">-p"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">3000"</span><span class="pi">]</span>
</code></pre></div></div>

<p><strong>How to run this?</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-compose up <span class="nt">-d</span>
</code></pre></div></div>

<p>This works great in development, but <strong>for production, we need Kubernetes</strong>.</p>

<hr />

<h2 id="convert-docker-compose-to-kubernetes-manifest-files">Convert Docker-Compose to Kubernetes Manifest Files</h2>
<p>The major config difference between docker-compose and kubernetes is, we write everything on a single manifest file when using docker-compose.</p>

<p>However, on Kubernetes, we need to create <strong>Kubernetes YAML files</strong> for each component:</p>

<p>✅ <strong>Deployments</strong> (for backend, frontend, database)<br />
✅ <strong>Services</strong> (to expose them inside Kubernetes)<br />
✅ <strong>Persistent Volume for PostgreSQL</strong></p>

<h3 id="project-structure"><strong>Project Structure</strong></h3>
<p>So, this is what a similar full-stack service with three components project structure would look like if we wanna deploy on Kubernetes.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>k8s-app/
│── db/
│   ├── db-deployment.yaml
│   ├── db-service.yaml
│── backend/
│   ├── backend-deployment.yaml
│   ├── backend-service.yaml
│── frontend/
│   ├── frontend-deployment.yaml
│   ├── frontend-service.yaml
│── namespace.yaml
</code></pre></div></div>

<hr />

<h3 id="database-deployment-postgresql"><strong>Database Deployment (PostgreSQL)</strong></h3>

<p><strong>db/db-deployment.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">postgres</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">1</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">postgres</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">postgres</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">postgres</span>
        <span class="na">image</span><span class="pi">:</span> <span class="s">postgres:15</span>
        <span class="na">env</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">POSTGRES_USER</span>
          <span class="na">value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">user"</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">POSTGRES_PASSWORD</span>
          <span class="na">value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">password"</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">POSTGRES_DB</span>
          <span class="na">value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">mydatabase"</span>
        <span class="na">ports</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">5432</span>
</code></pre></div></div>

<p><strong>db/db-service.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">postgres</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> <span class="s">postgres</span>
  <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>
      <span class="na">port</span><span class="pi">:</span> <span class="m">5432</span>
      <span class="na">targetPort</span><span class="pi">:</span> <span class="m">5432</span>
</code></pre></div></div>

<hr />

<h3 id="backend-deployment"><strong>Backend Deployment</strong></h3>

<p><strong>backend/backend-deployment.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">backend</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">1</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">backend</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">backend</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">backend</span>
        <span class="na">image</span><span class="pi">:</span> <span class="s">python:3.10</span>
        <span class="na">env</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">DATABASE_URL</span>
          <span class="na">value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">postgresql://user:password@postgres:5432/mydatabase"</span>
        <span class="na">ports</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">5000</span>
        <span class="na">command</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">python"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">-m"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">http.server"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">5000"</span><span class="pi">]</span>
</code></pre></div></div>

<p><strong>backend/backend-service.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">backend</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> <span class="s">backend</span>
  <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>
      <span class="na">port</span><span class="pi">:</span> <span class="m">5000</span>
      <span class="na">targetPort</span><span class="pi">:</span> <span class="m">5000</span>
</code></pre></div></div>

<hr />

<h3 id="frontend-deployment"><strong>Frontend Deployment</strong></h3>

<p><strong>frontend/frontend-deployment.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">frontend</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">1</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">frontend</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">frontend</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">frontend</span>
        <span class="na">image</span><span class="pi">:</span> <span class="s">node:18</span>
        <span class="na">ports</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">3000</span>
        <span class="na">command</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">npx"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">http-server"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">-p"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">3000"</span><span class="pi">]</span>
</code></pre></div></div>

<p><strong>frontend/frontend-service.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">frontend</span>
  <span class="na">namespace</span><span class="pi">:</span> <span class="s">myapp</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> <span class="s">frontend</span>
  <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>
      <span class="na">port</span><span class="pi">:</span> <span class="m">3000</span>
      <span class="na">targetPort</span><span class="pi">:</span> <span class="m">3000</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">NodePort</span>

</code></pre></div></div>

<hr />

<h3 id="namespace-file"><strong>Namespace File</strong></h3>

<p><strong>namespace.yaml</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Namespace</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">myapp</span>
</code></pre></div></div>

<hr />

<h2 id="deploy-the-application-on-minikube">Deploy the Application on Minikube</h2>

<p>1️⃣ <strong>Start Minikube</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minikube start
</code></pre></div></div>

<p>2️⃣ <strong>Apply Kubernetes manifests</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> namespace.yaml
kubectl apply <span class="nt">-f</span> db/db-deployment.yaml
kubectl apply <span class="nt">-f</span> db/db-service.yaml
kubectl apply <span class="nt">-f</span> backend/backend-deployment.yaml
kubectl apply <span class="nt">-f</span> backend/backend-service.yaml
kubectl apply <span class="nt">-f</span> frontend/frontend-deployment.yaml
kubectl apply <span class="nt">-f</span> frontend/frontend-service.yaml
</code></pre></div></div>

<p>3️⃣ <strong>Check the status</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get all <span class="nt">-n</span> myapp
</code></pre></div></div>

<p>4️⃣ <strong>Get frontend service URL</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minikube service frontend <span class="nt">-n</span> myapp
</code></pre></div></div>

<p><strong>Now we have deployed your full-stack app on Minikube!</strong></p>

<hr />

<h2 id="remarks">Remarks</h2>

<p><strong>Key Takeaways</strong><br />
✅ <strong>Docker-Compose</strong> is great for local development.<br />
✅ <strong>Kubernetes manifests</strong> provide scalability, high availability, and production readiness.<br />
✅ Minikube helps us <strong>test Kubernetes locally</strong> before deploying to the cloud.</p>

<p><strong>Next Steps</strong></p>

<ul>
  <li>Add a <strong>Kubernetes Ingress Controller</strong></li>
  <li>Implement <strong>ConfigMaps &amp; Secrets</strong> for better security</li>
  <li>Use <strong>Helm Charts</strong> to manage deployment configurations</li>
</ul>

<!--stackedit_data:
eyJoaXN0b3J5IjpbNzEwNzI4ODkzXX0=
-->]]></content><author><name>Shanto Roy</name></author><category term="Kubernetes" /><category term="Kubernetes" /><category term="Docker-Compose" /><category term="DevOps" /><category term="SRE" /><category term="Minikube" /><summary type="html"><![CDATA[Learn how to convert a Docker-Compose setup into Kubernetes manifest files. We will deploy a Python-based frontend, backend, and PostgreSQL database on Minikube.]]></summary></entry><entry><title type="html">#100daysofSRE (Day 30): Learn Kubernetes Commands and Operations using Minikube</title><link href="https://shantoroy.com/kubernetes/learn-kubernetes-commands-operations-using-minikube/" rel="alternate" type="text/html" title="#100daysofSRE (Day 30): Learn Kubernetes Commands and Operations using Minikube" /><published>2025-03-10T00:00:00+00:00</published><updated>2025-03-10T00:00:00+00:00</updated><id>https://shantoroy.com/kubernetes/learn-kubernetes-commands-operations-using-minikube</id><content type="html" xml:base="https://shantoroy.com/kubernetes/learn-kubernetes-commands-operations-using-minikube/"><![CDATA[<p>Minikube is an excellent tool to <strong>practice Kubernetes operations</strong> in a local environment.</p>

<p>This post provides a <strong>cheatsheet</strong> of essential commands followed by <strong>scenario-based examples</strong> to simulate real-world Kubernetes tasks.</p>

<hr />

<h2 id="kubernetes-command-cheatsheet">Kubernetes Command Cheatsheet</h2>

<h3 id="-minikube-management">🔹 Minikube Management</h3>

<table>
  <thead>
    <tr>
      <th>Task</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Start Minikube cluster</td>
      <td><code class="language-plaintext highlighter-rouge">minikube start</code></td>
    </tr>
    <tr>
      <td>Stop Minikube</td>
      <td><code class="language-plaintext highlighter-rouge">minikube stop</code></td>
    </tr>
    <tr>
      <td>Delete Minikube cluster</td>
      <td><code class="language-plaintext highlighter-rouge">minikube delete</code></td>
    </tr>
    <tr>
      <td>Check Minikube status</td>
      <td><code class="language-plaintext highlighter-rouge">minikube status</code></td>
    </tr>
    <tr>
      <td>Open Minikube dashboard</td>
      <td><code class="language-plaintext highlighter-rouge">minikube dashboard</code></td>
    </tr>
  </tbody>
</table>

<h3 id="-cluster--node-information">🔹 Cluster &amp; Node Information</h3>

<table>
  <thead>
    <tr>
      <th>Task</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>View cluster information</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl cluster-info</code></td>
    </tr>
    <tr>
      <td>Get all nodes</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl get nodes</code></td>
    </tr>
    <tr>
      <td>Describe a node</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl describe node &lt;node-name&gt;</code></td>
    </tr>
  </tbody>
</table>

<h3 id="-managing-pods">🔹 Managing Pods</h3>

<table>
  <thead>
    <tr>
      <th>Task</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>List all running pods</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl get pods</code></td>
    </tr>
    <tr>
      <td>Describe a specific pod</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl describe pod &lt;pod-name&gt;</code></td>
    </tr>
    <tr>
      <td>View pod logs</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl logs &lt;pod-name&gt;</code></td>
    </tr>
    <tr>
      <td>Execute a command inside a pod</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl exec -it &lt;pod-name&gt; -- /bin/sh</code></td>
    </tr>
    <tr>
      <td>Delete a pod</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl delete pod &lt;pod-name&gt;</code></td>
    </tr>
  </tbody>
</table>

<h3 id="-managing-deployments">🔹 Managing Deployments</h3>

<table>
  <thead>
    <tr>
      <th>Task</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>List all deployments</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl get deployments</code></td>
    </tr>
    <tr>
      <td>Scale deployment replicas</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl scale deployment &lt;deployment-name&gt; --replicas=3</code></td>
    </tr>
    <tr>
      <td>Update an existing deployment</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl rollout restart deployment &lt;deployment-name&gt;</code></td>
    </tr>
    <tr>
      <td>Undo a deployment rollback</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl rollout undo deployment &lt;deployment-name&gt;</code></td>
    </tr>
  </tbody>
</table>

<h3 id="-exposing-services">🔹 Exposing Services</h3>

<table>
  <thead>
    <tr>
      <th>Task</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>List all services</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl get services</code></td>
    </tr>
    <tr>
      <td>Expose a deployment via NodePort</td>
      <td><code class="language-plaintext highlighter-rouge">kubectl expose deployment &lt;deployment-name&gt; --type=NodePort --port=80</code></td>
    </tr>
    <tr>
      <td>Get Minikube service URL</td>
      <td><code class="language-plaintext highlighter-rouge">minikube service &lt;service-name&gt; --url</code></td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="scenario-based-kubernetes-operations-in-minikube">Scenario-Based Kubernetes Operations in Minikube</h2>

<h3 id="scenario-1-deploy-a-simple-web-application"><strong>Scenario 1: Deploy a Simple Web Application</strong></h3>
<p><strong>Goal</strong>: Deploy an Nginx web server and expose it via a service.</p>

<h4 id="steps"><strong>Steps</strong>:</h4>
<p>1️⃣ Create a deployment for <strong>Nginx</strong></p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl create deployment nginx <span class="nt">--image</span><span class="o">=</span>nginx <span class="nt">--replicas</span><span class="o">=</span>2
</code></pre></div></div>

<p>2️⃣ Expose the deployment as a <strong>NodePort</strong> service</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl expose deployment nginx <span class="nt">--type</span><span class="o">=</span>NodePort <span class="nt">--port</span><span class="o">=</span>80
</code></pre></div></div>

<p>3️⃣ Get the external service URL using Minikube</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minikube service nginx <span class="nt">--url</span>
</code></pre></div></div>

<p>4️⃣ Open the application in a browser</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minikube service nginx
</code></pre></div></div>

<hr />

<h3 id="scenario-2-scale-an-application-dynamically"><strong>Scenario 2: Scale an Application Dynamically</strong></h3>

<p><strong>Goal</strong>: Scale the Nginx deployment from 2 to 5 replicas.</p>

<h4 id="steps-1"><strong>Steps</strong>:</h4>

<p>1️⃣ Check current pods</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get pods
</code></pre></div></div>

<p>2️⃣ Scale deployment</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl scale deployment nginx <span class="nt">--replicas</span><span class="o">=</span>5
</code></pre></div></div>

<p>3️⃣ Verify the scaling</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get pods
</code></pre></div></div>

<hr />

<h3 id="scenario-3-rolling-update--rollback"><strong>Scenario 3: Rolling Update &amp; Rollback</strong></h3>

<p><strong>Goal</strong>: Update the Nginx version and roll it back if something goes wrong.</p>

<h4 id="steps-2"><strong>Steps</strong>:</h4>

<p>1️⃣ Check the current deployment</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get deployments
</code></pre></div></div>

<p>2️⃣ Update the deployment to use <strong>nginx:1.23</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl <span class="nb">set </span>image deployment/nginx <span class="nv">nginx</span><span class="o">=</span>nginx:1.23
</code></pre></div></div>

<p>3️⃣ Check the rollout status</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl rollout status deployment/nginx
</code></pre></div></div>

<p>4️⃣ If the new version is unstable, rollback</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl rollout undo deployment/nginx
</code></pre></div></div>

<hr />

<h3 id="scenario-4-debugging-a-failing-pod"><strong>Scenario 4: Debugging a Failing Pod</strong></h3>

<p><strong>Goal</strong>: Troubleshoot a pod that is stuck in <code class="language-plaintext highlighter-rouge">CrashLoopBackOff</code>.</p>

<h4 id="steps-3"><strong>Steps</strong>:</h4>

<p>1️⃣ List pods and find the problematic one</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl get pods
</code></pre></div></div>

<p>2️⃣ Check pod logs</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl logs &lt;pod-name&gt;
</code></pre></div></div>

<p>3️⃣ Describe the pod for detailed information</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl describe pod &lt;pod-name&gt;
</code></pre></div></div>

<p>4️⃣ Get into the pod’s shell (if running)</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl <span class="nb">exec</span> <span class="nt">-it</span> &lt;pod-name&gt; <span class="nt">--</span> /bin/sh
</code></pre></div></div>

<p>5️⃣ Delete and restart the pod</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl delete pod &lt;pod-name&gt;
</code></pre></div></div>

<hr />

<h3 id="scenario-5-deploying-a-multi-tier-app-with-minikube"><strong>Scenario 5: Deploying a Multi-Tier App with Minikube</strong></h3>

<p><strong>Goal</strong>: Deploy a <strong>frontend and backend</strong> in Kubernetes.</p>

<h4 id="steps-4"><strong>Steps</strong>:</h4>

<p>1️⃣ Deploy a <strong>backend API</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl create deployment backend <span class="nt">--image</span><span class="o">=</span>python:3.10-slim
</code></pre></div></div>

<p>2️⃣ Expose backend via a <strong>ClusterIP</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl expose deployment backend <span class="nt">--port</span><span class="o">=</span>5000 <span class="nt">--type</span><span class="o">=</span>ClusterIP
</code></pre></div></div>

<p>3️⃣ Deploy a <strong>React frontend</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl create deployment frontend <span class="nt">--image</span><span class="o">=</span>node:18-alpine
</code></pre></div></div>

<p>4️⃣ Expose frontend as a <strong>LoadBalancer</strong></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl expose deployment frontend <span class="nt">--port</span><span class="o">=</span>3000 <span class="nt">--type</span><span class="o">=</span>LoadBalancer
</code></pre></div></div>

<p>5️⃣ Get the service URL</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minikube service frontend
</code></pre></div></div>

<p><strong>Now we have a full-stack app running in Kubernetes!</strong></p>

<hr />

<h2 id="remarks">Remarks</h2>

<p>Minikube is a powerful tool for <strong>learning and testing Kubernetes commands</strong> in a local environment.</p>

<p>By practicing these <strong>scenario-based tasks</strong>, we can become comfortable with <strong>real-world Kubernetes operations</strong> before deploying in production.</p>

<p><strong>Key Takeaways</strong></p>

<ul>
  <li>Minikube helps you <strong>test Kubernetes locally</strong>.</li>
  <li>You can create, scale, and troubleshoot applications easily.</li>
  <li>Kubernetes commands allow <strong>rolling updates, service exposure, and debugging</strong> in a structured way.</li>
</ul>

<p><strong>Next Steps</strong></p>

<ul>
  <li>Try deploying <strong>stateful applications</strong> with <strong>Persistent Volumes</strong>.</li>
  <li>Experiment with <strong>Ingress controllers</strong> in Minikube.</li>
  <li>Learn about <strong>Kubernetes Helm Charts</strong> for app deployment automation.</li>
</ul>

<p><strong>Stay tuned for more Kubernetes posts in the #100DaysOfSRE series!</strong>
<!--stackedit_data:
eyJoaXN0b3J5IjpbOTI4Njc0OTU0XX0=
--></p>]]></content><author><name>Shanto Roy</name></author><category term="Kubernetes" /><category term="Kubernetes" /><category term="Minikube" /><category term="DevOps" /><category term="SRE" /><category term="Containers" /><summary type="html"><![CDATA[Master Kubernetes with Minikube! This post provides a cheatsheet of essential commands and walks through real-world scenarios to help you practice deployments, scaling, troubleshooting, and networking in a local Kubernetes environment.]]></summary></entry><entry><title type="html">#100daysofSRE (Day 29): Kubernetes over Docker-compose – Why It’s Better for Production</title><link href="https://shantoroy.com/sre/kubernetes-for-production-grade-applications/" rel="alternate" type="text/html" title="#100daysofSRE (Day 29): Kubernetes over Docker-compose – Why It’s Better for Production" /><published>2025-03-09T00:00:00+00:00</published><updated>2025-03-09T00:00:00+00:00</updated><id>https://shantoroy.com/sre/kubernetes-for-production-grade-applications</id><content type="html" xml:base="https://shantoroy.com/sre/kubernetes-for-production-grade-applications/"><![CDATA[<p>So far until now, we have learned how docker-compose can be a go-to tool for deploying and testing containerized applications locally. However, when it comes to enterprise production, we don’t use docker-compose. In this post we will learn how Kubernetes replaces docker-compose for enterprise-level production-grade deployment.</p>

<p>Kubernetes (K8s) is an <strong>open-source container orchestration platform</strong> designed to <strong>automate the deployment, scaling, and management of containerized applications</strong>.</p>

<p>It helps organizations <strong>deploy applications at scale</strong>, handle <strong>failures gracefully</strong>, and manage <strong>hundreds or thousands of containers</strong> efficiently.</p>

<h3 id="key-features-of-kubernetes">Key Features of Kubernetes:</h3>
<p>✅ <strong>Self-healing</strong> – Restarts failed containers automatically<br />
✅ <strong>Auto-scaling</strong> – Adjusts resources based on real-time demand<br />
✅ <strong>Service discovery &amp; load balancing</strong> – Built-in traffic management<br />
✅ <strong>Rolling updates &amp; rollbacks</strong> – Ensures zero-downtime deployments<br />
✅ <strong>Multi-cloud &amp; hybrid-cloud support</strong> – Runs on AWS, GCP, Azure, on-prem, etc.</p>

<hr />

<h2 id="-kubernetes-vs-docker-compose--why-kubernetes-for-production">🐳 Kubernetes vs. Docker Compose – Why Kubernetes for Production?</h2>

<p>While <strong>Docker Compose</strong> is great for local development, <strong>Kubernetes</strong> is the preferred solution for <strong>enterprise production deployments</strong>.</p>

<table>
  <thead>
    <tr>
      <th>Feature</th>
      <th>Docker Compose 🐳</th>
      <th>Kubernetes ☸️</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Scalability</strong></td>
      <td>Manual scaling</td>
      <td>Auto-scaling based on demand</td>
    </tr>
    <tr>
      <td><strong>Load Balancing</strong></td>
      <td>No built-in support</td>
      <td>Integrated Service Load Balancer</td>
    </tr>
    <tr>
      <td><strong>Self-Healing</strong></td>
      <td>Containers crash without auto-restart</td>
      <td>Automatically restarts failed pods</td>
    </tr>
    <tr>
      <td><strong>High Availability</strong></td>
      <td>Single-node setup</td>
      <td>Multi-node cluster setup</td>
    </tr>
    <tr>
      <td><strong>Rolling Updates</strong></td>
      <td>Requires manual intervention</td>
      <td>Seamless rolling updates &amp; rollbacks</td>
    </tr>
    <tr>
      <td><strong>Cloud-Native</strong></td>
      <td>Limited to local development</td>
      <td>Runs on AWS, GCP, Azure, on-prem</td>
    </tr>
    <tr>
      <td><strong>Networking</strong></td>
      <td>Limited to local Docker network</td>
      <td>Advanced networking with Service Mesh (Istio, Cilium)</td>
    </tr>
    <tr>
      <td><strong>Storage</strong></td>
      <td>Simple volume management</td>
      <td>Persistent storage across multiple nodes</td>
    </tr>
  </tbody>
</table>

<p>💡 <strong>TL;DR:</strong> Docker Compose is great for testing and development, but <strong>Kubernetes is the industry standard for production</strong> because it provides <strong>better automation, scalability, resilience, and multi-cloud support</strong>.</p>

<hr />

<h2 id="why-enterprises-choose-kubernetes">Why Enterprises Choose Kubernetes</h2>

<h3 id="1️⃣-handles-large-scale-deployments"><strong>1️⃣ Handles Large-Scale Deployments</strong></h3>
<p>For companies running <strong>thousands of microservices</strong>, Kubernetes makes scaling effortless with <strong>Horizontal Pod Autoscaling (HPA)</strong>.</p>

<p>Example:</p>
<ul>
  <li><strong><a href="https://netflixtechblog.com/kubernetes-and-kernel-panics-ed620b9c6225">Netflix</a>, <a href="https://www.uber.com/blog/odin-stateful-platform/">Uber</a>, and <a href="https://medium.com/airbnb-engineering/apache-flink-on-kubernetes-84425d66ee11">Airbnb</a></strong> use Kubernetes to manage <strong>thousands of microservices</strong> across cloud regions.</li>
</ul>

<h3 id="2️⃣-built-in-high-availability"><strong>2️⃣ Built-In High Availability</strong></h3>
<p>Kubernetes runs applications in <strong>multiple replicas</strong> across different nodes, ensuring <strong>zero downtime</strong> even if a node fails.</p>

<h3 id="3️⃣-cloud-native--multi-cloud-ready"><strong>3️⃣ Cloud-Native &amp; Multi-Cloud Ready</strong></h3>
<p>With <strong>AWS EKS, GCP GKE, and Azure AKS</strong>, enterprises can <strong>deploy Kubernetes clusters</strong> without vendor lock-in.</p>

<p>Example:</p>
<ul>
  <li><strong>Spotify</strong> migrated from on-prem servers to <strong>Google Kubernetes Engine (GKE)</strong> for better cloud scalability.</li>
</ul>

<h3 id="4️⃣-devops--gitops-friendly"><strong>4️⃣ DevOps &amp; GitOps Friendly</strong></h3>
<p>Kubernetes integrates seamlessly with <strong>CI/CD pipelines</strong> using <strong>ArgoCD, GitHub Actions, and Jenkins</strong> for automated deployments.</p>

<p>Example:</p>
<ul>
  <li><strong>Adobe</strong> uses Kubernetes with <strong>ArgoCD for GitOps</strong>, ensuring <strong>secure and automated deployments</strong>.</li>
</ul>

<h3 id="5️⃣-secure--policy-driven"><strong>5️⃣ Secure &amp; Policy-Driven</strong></h3>
<p>With tools like <strong>Kubernetes RBAC (Role-Based Access Control), Istio (Service Mesh), and Open Policy Agent (OPA)</strong>, enterprises can enforce <strong>strict security policies</strong>.</p>

<hr />

<h2 id="getting-started-with-kubernetes-locally">Getting Started with Kubernetes Locally</h2>
<h3 id="option-01-running-minikube-on-host">Option 01: Running Minikube on Host</h3>

<p>You can install a lightweight Kubernetes cluster on your local machine using <strong>Minikube</strong> or <strong>Kind</strong>.</p>

<ul>
  <li><strong>Install Minikube</strong>
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl <span class="nt">-LO</span> https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
<span class="nv">$ </span><span class="nb">sudo install </span>minikube-linux-amd64 /usr/local/bin/minikube
<span class="nv">$ </span>minikube start
</code></pre></div>    </div>
  </li>
  <li><strong>Deploy a Sample Application</strong></li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>kubectl create deployment my-app <span class="nt">--image</span><span class="o">=</span>nginx
<span class="nv">$ </span>kubectl expose deployment my-app <span class="nt">--type</span><span class="o">=</span>LoadBalancer <span class="nt">--port</span><span class="o">=</span>80
<span class="nv">$ </span>minikube service my-app
</code></pre></div></div>

<h3 id="option-02-testing-minikube-inside-docker">Option 02: Testing Minikube inside docker</h3>
<p>Running <strong>Minikube</strong> inside a <strong>Docker container</strong> is not straightforward because Minikube itself requires a virtualization layer (such as Docker, VirtualBox, or KVM) to create a Kubernetes cluster. However, you can run Minikube inside a Docker container using the <strong>none</strong> driver, which runs Kubernetes components directly on the host.</p>

<p>Here’s a <strong>Dockerfile</strong> that sets up a containerized environment to run Minikube using Docker as the driver:</p>

<hr />

<h4 id="dockerfile-for-running-minikube"><strong>Dockerfile for Running Minikube</strong></h4>

<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="s"> ubuntu:22.04</span>

<span class="c"># Set environment variables</span>
<span class="k">ENV</span><span class="s"> KUBECTL_VERSION=v1.27.3 \</span>
    MINIKUBE_VERSION=v1.30.1

<span class="c"># Install dependencies</span>
<span class="k">RUN </span>apt-get update <span class="o">&amp;&amp;</span> apt-get <span class="nb">install</span> <span class="nt">-y</span> <span class="se">\
</span>    curl <span class="se">\
</span>    ca-certificates <span class="se">\
</span>    conntrack <span class="se">\
</span>    iptables <span class="se">\
</span>    socat <span class="se">\
</span>    ebtables <span class="se">\
</span>    ethtool <span class="se">\
</span>    <span class="nb">sudo</span> <span class="se">\
</span>    docker.io <span class="se">\
</span>    <span class="o">&amp;&amp;</span> apt-get clean

<span class="c"># Install kubectl</span>
<span class="k">RUN </span>curl <span class="nt">-Lo</span> /usr/local/bin/kubectl https://dl.k8s.io/release/<span class="k">${</span><span class="nv">KUBECTL_VERSION</span><span class="k">}</span>/bin/linux/amd64/kubectl <span class="o">&amp;&amp;</span> <span class="se">\
</span>    <span class="nb">chmod</span> +x /usr/local/bin/kubectl

<span class="c"># Install Minikube</span>
<span class="k">RUN </span>curl <span class="nt">-Lo</span> /usr/local/bin/minikube https://storage.googleapis.com/minikube/releases/<span class="k">${</span><span class="nv">MINIKUBE_VERSION</span><span class="k">}</span>/minikube-linux-amd64 <span class="o">&amp;&amp;</span> <span class="se">\
</span>    <span class="nb">chmod</span> +x /usr/local/bin/minikube

<span class="c"># Create a non-root user</span>
<span class="k">RUN </span>useradd <span class="nt">-m</span> minikube <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"minikube:minikube"</span> | chpasswd <span class="o">&amp;&amp;</span> adduser minikube <span class="nb">sudo</span>
<span class="k">USER</span><span class="s"> minikube</span>
<span class="k">WORKDIR</span><span class="s"> /home/minikube</span>

<span class="c"># Start Minikube inside the container</span>
<span class="k">CMD</span><span class="s"> ["minikube", "start", "--driver=docker"]</span>
</code></pre></div></div>

<hr />

<h4 id="build--run-instructions"><strong>Build &amp; Run Instructions</strong></h4>

<ol>
  <li>
    <p><strong>Build the Docker image</strong></p>

    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> minikube-container <span class="nb">.</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Run the container with proper privileges</strong></p>

    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--privileged</span> <span class="nt">-v</span> /var/run/docker.sock:/var/run/docker.sock <span class="nt">-it</span> minikube-container
</code></pre></div>    </div>
  </li>
</ol>

<h4 id="explanation"><strong>Explanation</strong></h4>

<ul>
  <li><strong>Installs Minikube and kubectl</strong>: Necessary for running Kubernetes.</li>
  <li><strong>Uses Docker as a driver</strong>: Minikube will run its Kubernetes cluster inside Docker.</li>
  <li><strong>Non-root user setup</strong>: Helps prevent permission issues.</li>
  <li><strong>Maps Docker socket (<code class="language-plaintext highlighter-rouge">/var/run/docker.sock</code>)</strong>: Allows Minikube to create Docker containers inside the host.</li>
</ul>

<hr />

<h2 id="when-should-you-use-kubernetes">When Should You Use Kubernetes?</h2>

<table>
  <thead>
    <tr>
      <th>Scenario</th>
      <th>Use Docker Compose 🐳</th>
      <th>Use Kubernetes ☸️</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Local Development</strong></td>
      <td>✅ Yes</td>
      <td>❌ No</td>
    </tr>
    <tr>
      <td><strong>Small-Scale Apps</strong></td>
      <td>✅ Yes</td>
      <td>⚠️ Maybe</td>
    </tr>
    <tr>
      <td><strong>Enterprise Production</strong></td>
      <td>❌ No</td>
      <td>✅ Yes</td>
    </tr>
    <tr>
      <td><strong>Multi-Cloud Deployments</strong></td>
      <td>❌ No</td>
      <td>✅ Yes</td>
    </tr>
    <tr>
      <td><strong>High Availability Needed</strong></td>
      <td>❌ No</td>
      <td>✅ Yes</td>
    </tr>
    <tr>
      <td><strong>Auto-Scaling Required</strong></td>
      <td>❌ No</td>
      <td>✅ Yes</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="how-kubernetes-is-replacing-traditional-infrastructure">How Kubernetes is Replacing Traditional Infrastructure</h2>

<p>Kubernetes is <strong>revolutionizing IT infrastructure</strong> by shifting organizations from traditional <strong>physical servers and IaaS (Infrastructure-as-a-Service) to modern, container-based deployments</strong>. Here’s how:</p>

<p>1️⃣ <strong>From Monolith to Microservices</strong>:</p>
<ul>
  <li>Legacy applications are being <strong>refactored into microservices</strong> using Kubernetes, allowing <strong>faster development, deployment, and scaling</strong>.</li>
</ul>

<p>2️⃣ <strong>Replacing Physical Servers &amp; VMs</strong>:</p>
<ul>
  <li>Instead of managing <strong>dedicated physical servers or virtual machines (VMs)</strong>, companies are deploying applications in <strong>lightweight, scalable Kubernetes pods</strong>.</li>
</ul>

<p>3️⃣ <strong>Auto-Scaling &amp; Dynamic Resource Allocation</strong>:</p>
<ul>
  <li>Unlike traditional IaaS where <strong>resources are statically allocated</strong>, Kubernetes uses <strong>Horizontal Pod Autoscaling (HPA)</strong> to adjust based on demand, optimizing costs.</li>
</ul>

<p>4️⃣ <strong>Cloud-Agnostic Deployments</strong>:</p>
<ul>
  <li>Kubernetes abstracts the underlying infrastructure, enabling <strong>seamless workload portability</strong> across <strong>AWS, GCP, Azure, and on-prem</strong>.</li>
</ul>

<p>5️⃣ <strong>Modernizing Legacy Apps Without Rewriting</strong>:</p>
<ul>
  <li>Using Kubernetes and <strong>containerization (Docker)</strong>, enterprises can <strong>package legacy applications</strong> into containers, <strong>eliminating dependencies on outdated OS or hardware</strong>.</li>
</ul>

<p>6️⃣ <strong>Enhanced Reliability &amp; Zero Downtime Deployments</strong>:</p>
<ul>
  <li>Kubernetes’ <strong>rolling updates, automatic failover, and self-healing capabilities</strong> ensure applications remain available <strong>without manual intervention</strong>.</li>
</ul>

<p>💡 <strong>The Future</strong>: Traditional infrastructure is being phased out as Kubernetes becomes the <strong>de facto standard</strong> for managing <strong>cloud-native, scalable, and resilient applications</strong> in <strong>modern enterprises</strong>.</p>

<hr />

<h2 id="remarks">Remarks</h2>

<p><strong>Docker Compose</strong> is great for <strong>local development and small projects</strong>, but <strong>Kubernetes</strong> is the <strong>best choice for production</strong>, especially for <strong>enterprise-scale applications</strong>.</p>

<p>✅ <strong>Kubernetes is built for automation, scalability, and reliability.</strong><br />
✅ <strong>It’s cloud-native and supports multi-cloud &amp; hybrid-cloud deployments.</strong><br />
✅ <strong>Enterprises trust Kubernetes for mission-critical workloads.</strong></p>

<p>When I first develop a backend or frontend, docker-compose is my go-to solution. You will find many docker-compose projects on my <a href="https://github.com/shantoroy">GitHub</a>. However, when it comes to production, we definitely need to use Kubernetes. I have collected some templates from high-starred github repos and putting in one on <a href="https://github.com/shantoroy/kubernetes-yaml-templates">Kubernetes Template Collections</a>.</p>

<!--stackedit_data:
eyJoaXN0b3J5IjpbLTI1MzMzNTg1NywxNTI5MjYwNDE1LDE3MD
c2NzEwNjVdfQ==
-->]]></content><author><name>Shanto Roy</name></author><category term="SRE" /><category term="SRE" /><category term="100daysofsre" /><category term="100daychallenge" /><category term="devops" /><category term="docker" /><category term="kubernetes" /><category term="containers" /><category term="cloud" /><summary type="html"><![CDATA[Learn why Kubernetes is the go-to solution for production deployments, replacing Docker Compose with enterprise-grade scalability, reliability, and automation.]]></summary></entry><entry><title type="html">#100daysofSRE (Day 28): Deploying an AI Chatbot with Docker Compose</title><link href="https://shantoroy.com/sre/building-a-genai-chatbot-using-docker-compose/" rel="alternate" type="text/html" title="#100daysofSRE (Day 28): Deploying an AI Chatbot with Docker Compose" /><published>2025-03-08T00:00:00+00:00</published><updated>2025-03-08T00:00:00+00:00</updated><id>https://shantoroy.com/sre/building-a-genai-chatbot-using-docker-compose</id><content type="html" xml:base="https://shantoroy.com/sre/building-a-genai-chatbot-using-docker-compose/"><![CDATA[<p><strong>AI chatbots</strong> have become an essential tool for businesses, developers, and researchers. They help in <strong>automated support, knowledge retrieval, and content generation</strong>. But running an AI chatbot efficiently requires proper deployment techniques.</p>

<p>In this post, we explore how <strong>Docker Compose</strong> simplifies the deployment of an <strong>AI-powered Retrieval-Augmented Generation (RAG) chatbot</strong>. This system:</p>
<ul>
  <li>Uses <strong>Ollama</strong> to run <strong>local LLMs</strong> (no cloud dependency)</li>
  <li>Implements <strong>FAISS for vector search</strong> to retrieve documents efficiently</li>
  <li>Provides a <strong>modern chat UI</strong> using <strong>Chainlit</strong></li>
  <li>Utilizes <strong>FastAPI</strong> for a high-performance backend</li>
  <li>Is <strong>fully containerized</strong>, making it easy to deploy</li>
</ul>

<p>Since this project is quite big, I’ll not go through the frontend or backend codes. I’ll just go through how I utilized docker-compose to build and run the project efficiently on my macbook pro.</p>

<p>Please, check out the whole project on my <a href="https://github.com/shantoroy/rag-chatbot-python-fullstack-template/tree/main">Github Repository</a>.</p>

<hr />

<h2 id="system-architecture">System Architecture</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>        
User ───────────────▶ Chainlit UI       Documents (txt/md/pdf)
                           │                     │
                           │                     │
                    Query  │                     │ Retrieve
                           │                     │ Documents
                           ▼                     ▼
                       FastAPI ◄───────────  RAG Model ◄─────── Local Ollama
                       Backend                   │
                           │                     │
                           └─────────────────────┘
                                Return Answer
</code></pre></div></div>

<p>The chatbot takes a user’s query, retrieves relevant information from stored documents, and generates a response using a local LLM.</p>

<hr />
<h2 id="getting-started">Getting Started</h2>

<h3 id="prerequisites">Prerequisites</h3>

<ul>
  <li><strong>Docker &amp; Docker Compose</strong></li>
  <li><strong>Ollama (for running local models)</strong></li>
  <li><strong>Python 3.10+</strong></li>
</ul>

<hr />
<h3 id="step-1-install-ollama">Step 1: Install Ollama</h3>

<p>Ollama is required to run local LLM models efficiently.</p>

<h4 id="macos"><strong>MacOS</strong></h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>ollama
brew services start ollama
</code></pre></div></div>

<h4 id="linux"><strong>Linux</strong></h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-fsSL</span> https://ollama.com/install.sh | sh
</code></pre></div></div>

<h4 id="windows"><strong>Windows</strong></h4>

<p>Download and install Ollama from the <strong><a href="https://ollama.com">official Ollama website</a></strong>.</p>

<hr />

<h3 id="step-2-download-required-llm-models">Step 2: Download Required LLM Models</h3>

<p>Run the following commands to ensure you have the required models:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ollama run mistral
ollama run nomic-embed-text
</code></pre></div></div>

<p>These models handle <strong>document embeddings</strong> and <strong>language generation</strong> for accurate responses.</p>

<hr />

<h3 id="step-3-clone-the-chatbot-repository">Step 3: Clone the Chatbot Repository</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/shantoroy/rag-chatbot-python-fullstack-template.git
<span class="nb">cd </span>rag-chatbot-python-fullstack-template
</code></pre></div></div>

<hr />

<h3 id="step-4-configure-the-environment">Step 4: Configure the Environment</h3>

<p>Copy <code class="language-plaintext highlighter-rouge">.env.example</code> to <code class="language-plaintext highlighter-rouge">.env</code> and modify it as needed.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp</span> .env.example .env
</code></pre></div></div>

<hr />

<h3 id="step-5-deploy-with-docker-compose">Step 5: Deploy with Docker Compose</h3>

<p><strong>Build and start the containers:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-compose build
docker-compose up <span class="nt">-d</span>
</code></pre></div></div>

<hr />

<h2 id="how-it-works">How It Works</h2>

<p>Once the containers are running:</p>

<ol>
  <li>Access the chatbot interface at <strong><a href="http://localhost:8505">http://localhost:8505</a></strong>.</li>
  <li>Upload your documents (txt, md, pdf) to the <code class="language-plaintext highlighter-rouge">/documents</code> directory.</li>
  <li>Ask questions in <strong>natural language</strong>.</li>
  <li>The system retrieves relevant information and generates an AI response.</li>
</ol>

<hr />

<h2 id="project-structure">Project Structure</h2>
<p>I wanted to have the project as structured as possible. So, you’ll find the backend and frontend application/api codes on corresponding folders.</p>

<p>The folder <code class="language-plaintext highlighter-rouge">docker</code> includes the Dockerfiles for the backend and the frontend. Since, both backend and frontend is developed in python, there are two requirements.txt files under the folder <code class="language-plaintext highlighter-rouge">requirements</code>.</p>

<p>This is a RAG-based AI chatbot and I’ve added functionalities to add three types of files under the <code class="language-plaintext highlighter-rouge">documents</code> folder: txt files, pdf files, and markdown files.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rag-chatbot-python-fullstack-template/
├── backend/
│   ├── model.py          # RAG model implementation
│   └── api.py            # FastAPI backend
├── frontend/
│   └── app.py            # Chainlit chat interface
├── docker/
│   ├── backend.Dockerfile
│   └── frontend.Dockerfile
├── requirements/
│   ├── backend_requirements.txt
│   └── frontend_requirements.txt
├── documents/            # Put/organize your documents here
│   ├── test_file_1.txt 
│   └── test_file_2.md
├── .env.example          # Example file, rename to .env
├── docker-compose.yml    # Service orchestration
└── README.md
</code></pre></div></div>

<hr />

<h2 id="docker-compose-file">Docker Compose File</h2>
<p>I included the backend and the frontend on the docker-compose file. Now, I was running this on my macbook pro and I heard somewhere that the ollama models cannot utilize the GPUs if run within a container.</p>

<p>So, here, you’ll not see ollama service on the dockerfile. But, you can actually run or test it on container. Ollama is properly optimized to run on personal computers. So, shouldn’t be an issue.</p>

<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code>services:

  backend:
    build:
      context: .
      dockerfile: docker/backend.Dockerfile
    environment:
      - OLLAMA_URL=http://host.docker.internal:11434
    ports:
      - "8000:8000"
    volumes:
      - ./documents:/app/documents
    user: "${UID:-1000}:${GID:-1000}"
    restart: unless-stopped

  frontend:
    build:
      context: .
      dockerfile: docker/frontend.Dockerfile
    ports:
      - "8505:8505"
    environment:
      - BACKEND_URL=http://backend:8000
      - CHAINLIT_AUTH_SECRET=${CHAINLIT_AUTH_SECRET}
    volumes:
      - ./frontend/src:/app/frontend/src
      - ./frontend/public:/app/frontend/public
    depends_on:
      - backend
    restart: unless-stopped
</code></pre></div></div>

<hr />

<h2 id="dockerfiles">Dockerfiles</h2>

<h3 id="frontend-dockerfile">Frontend Dockerfile</h3>
<p>The frontend dockerfile is fairly simple. You install requirements, copy the codes, and run the frontend based on <a href="https://docs.chainlit.io/get-started/overview">chainlit</a>.</p>

<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="s"> python:3.10-slim</span>

<span class="k">WORKDIR</span><span class="s"> /app</span>

<span class="c"># Copy requirements and install dependencies</span>
<span class="k">COPY</span><span class="s"> requirements/frontend_requirements.txt .</span>
<span class="k">RUN </span>pip <span class="nb">install</span> <span class="nt">--no-cache-dir</span> <span class="nt">-r</span> frontend_requirements.txt

<span class="c"># Copy application code and Chainlit config</span>
<span class="k">COPY</span><span class="s"> frontend /app/frontend</span>
<span class="k">COPY</span><span class="s"> chainlit.md /app/chainlit.md</span>

<span class="c"># Command to run the frontend</span>
<span class="k">CMD</span><span class="s"> ["chainlit", "run", "frontend/app.py", "--host", "0.0.0.0", "--port", "8505"]</span>
</code></pre></div></div>

<h3 id="backend-dockerfile">Backend Dockerfile</h3>
<p>The backend dockerfile is a bit challenging since it requires many prerequisites steps to run the underlying natural language processing tasks.</p>

<p>First, we need to install necessary linux packages installed. Then we install necessary modules from the requirements.txt file. Then we have to download <code class="language-plaintext highlighter-rouge">nltk</code> packages or libraries and set the environment variables.</p>

<p>On this project, I’m keeping the documents under backend. But, you can declare a separate volume space to store the documents you want your model to go through. You can define that volume on the docker-compose file.</p>

<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="s"> python:3.10-slim</span>

<span class="c"># Set the working directory</span>
<span class="k">WORKDIR</span><span class="s"> /app</span>

<span class="c"># Install system dependencies</span>
<span class="k">RUN </span>apt-get update <span class="o">&amp;&amp;</span> apt-get <span class="nb">install</span> <span class="nt">-y</span> <span class="se">\
</span>    build-essential <span class="se">\
</span>    libmagic1 <span class="se">\
</span>    file <span class="se">\
</span>    unzip <span class="se">\
</span>    wget <span class="se">\
</span>    poppler-utils <span class="se">\
</span>    tesseract-ocr <span class="se">\
</span>    pandoc <span class="se">\
</span>    libxml2-dev <span class="se">\
</span>    libxslt1-dev <span class="se">\
</span>    python3-dev <span class="se">\
</span>    <span class="o">&amp;&amp;</span> <span class="nb">rm</span> <span class="nt">-rf</span> /var/lib/apt/lists/<span class="k">*</span>

<span class="c"># Copy requirements first (to leverage Docker layer caching)</span>
<span class="k">COPY</span><span class="s"> requirements/backend_requirements.txt .</span>

<span class="c"># Install Python dependencies</span>
<span class="k">RUN </span>pip <span class="nb">install</span> <span class="nt">--no-cache-dir</span> <span class="nt">-r</span> backend_requirements.txt

<span class="c"># Download all necessary NLTK data</span>
<span class="k">RUN </span>python <span class="nt">-m</span> nltk.downloader <span class="nt">-d</span> /usr/local/share/nltk_data all
<span class="c"># Alternatively, if you want to download only specific packages:</span>
<span class="c"># RUN python -c "import nltk; \</span>
<span class="c">#     nltk.download('punkt', download_dir='/usr/local/share/nltk_data'); \</span>
<span class="c">#     nltk.download('averaged_perceptron_tagger', download_dir='/usr/local/share/nltk_data'); \</span>
<span class="c">#     nltk.download('punkt_tab', download_dir='/usr/local/share/nltk_data'); \</span>
<span class="c">#     nltk.download('tokenizers', download_dir='/usr/local/share/nltk_data')"</span>

<span class="c"># Set environment variable for NLTK data</span>
<span class="k">ENV</span><span class="s"> NLTK_DATA=/usr/local/share/nltk_data</span>

<span class="c"># Copy application code</span>
<span class="k">COPY</span><span class="s"> backend /app/backend</span>

<span class="c"># Create necessary directories</span>
<span class="k">RUN </span><span class="nb">mkdir</span> <span class="nt">-p</span> /app/documents /app/vector_store

<span class="c"># Set permissions for appuser</span>
<span class="k">RUN </span>useradd <span class="nt">-m</span> appuser <span class="o">&amp;&amp;</span> <span class="se">\
</span>    <span class="nb">chown</span> <span class="nt">-R</span> appuser:appuser /app/documents <span class="o">&amp;&amp;</span> <span class="se">\
</span>    <span class="nb">chown</span> <span class="nt">-R</span> appuser:appuser /app/vector_store <span class="o">&amp;&amp;</span> <span class="se">\
</span>    <span class="nb">chown</span> <span class="nt">-R</span> appuser:appuser /app/backend <span class="o">&amp;&amp;</span> <span class="se">\
</span>    <span class="nb">chown</span> <span class="nt">-R</span> appuser:appuser /usr/local/share/nltk_data

<span class="c"># Switch to non-root user</span>
<span class="k">USER</span><span class="s"> appuser</span>

<span class="c"># Set the working directory inside backend</span>
<span class="k">WORKDIR</span><span class="s"> /app/backend</span>

<span class="c"># Expose the port</span>
<span class="k">EXPOSE</span><span class="s"> 8000</span>

<span class="c"># Run the backend</span>
<span class="k">CMD</span><span class="s"> ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]</span>
</code></pre></div></div>

<hr />

<h2 id="stopping--cleaning-up">Stopping &amp; Cleaning Up</h2>

<p>To stop the chatbot services:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-compose down
</code></pre></div></div>

<p>To remove all associated containers, volumes, and images:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-compose down <span class="nt">-v</span>
docker system prune <span class="nt">-a</span>
</code></pre></div></div>

<hr />

<h2 id="remarks">Remarks</h2>

<p>Deploying an <strong>AI Chatbot</strong> using <strong>Docker Compose</strong> makes it <strong>easier to manage, deploy, and scale</strong>.<br />
💡 <strong>No need to manually configure dependencies</strong><br />
💡 <strong>Works on any system with Docker installed</strong><br />
💡 <strong>Leverages local LLMs for privacy and performance</strong></p>

<p>Please, check out the whole project on my <a href="https://github.com/shantoroy/rag-chatbot-python-fullstack-template/tree/main">Github Repository</a>.
<!--stackedit_data:
eyJoaXN0b3J5IjpbLTIxMzM3Njg0NDRdfQ==
--></p>]]></content><author><name>Shanto Roy</name></author><category term="SRE" /><category term="SRE" /><category term="100daysofsre" /><category term="100daychallenge" /><category term="devops" /><category term="docker" /><category term="AI" /><category term="chatbot" /><category term="RAG" /><category term="LLM" /><summary type="html"><![CDATA[Learn how to deploy a Retrieval-Augmented Generation (RAG) Chatbot using Docker Compose. This AI-powered system leverages local LLMs for privacy, FAISS for vector search, and FastAPI for a high-performance backend.]]></summary></entry></feed>