<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[DevOps Journey]]></title><description><![CDATA[DevOps Journey]]></description><link>https://mukundhan24.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 06 Oct 2026 13:10:38 GMT</lastBuildDate><atom:link href="https://mukundhan24.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[🐳 My Kubernetes Three-Tier Demo: A Journey into Pods, Services, Ingress, and PVCs]]></title><description><![CDATA[When I started my DevOps journey, one of the things that confused me the most was networking inside Kubernetes.
How do the UI, backend, and database pods talk to each other? Why do we need Services? And what role does Ingress play?
To answer these qu...]]></description><link>https://mukundhan24.hashnode.dev/my-kubernetes-three-tier-demo-a-journey-into-pods-services-ingress-and-pvcs</link><guid isPermaLink="true">https://mukundhan24.hashnode.dev/my-kubernetes-three-tier-demo-a-journey-into-pods-services-ingress-and-pvcs</guid><category><![CDATA[#kubernetes #devops #cloud]]></category><category><![CDATA[#Kubernetes #DevOps #CloudComputing #Security #StorageManagement]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Cloud Computing]]></category><dc:creator><![CDATA[Mukundhan S]]></dc:creator><pubDate>Sat, 27 Sep 2025 12:38:43 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-when-i-started-my-devops-journey-one-of-the-things-that-confused-me-the-most-was-networking-inside-kubernetes">When I started my DevOps journey, one of the things that confused me the most was networking inside Kubernetes.</h3>
<p>How do the UI, backend, and database pods talk to each other? Why do we need Services? And what role does Ingress play?</p>
<p>To answer these questions, I built a <strong>small three-tier demo app</strong>:</p>
<ul>
<li><p>A <strong>UI</strong> pod (frontend)</p>
</li>
<li><p>A <strong>Business Service (BS)</strong> pod (backend API)</p>
</li>
<li><p>A <strong>Database (Postgres)</strong> pod (storage)</p>
</li>
</ul>
<p>The goal was simple → make them talk to each other inside Minikube, and expose the UI through an Ingress so I can open it in my browser.</p>
<p>This blog is my step-by-step journey, written in beginner-friendly language.</p>
<hr />
<h2 id="heading-prerequisites">🛠 Prerequisites</h2>
<p>I used Ubuntu WSL with Minikube. The setup steps:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Start Minikube</span>
minikube start --cpus=4 --memory=6g --driver=docker

<span class="hljs-comment"># Enable ingress controller</span>
minikube addons <span class="hljs-built_in">enable</span> ingress

<span class="hljs-comment"># Create namespace for this demo</span>
kubectl create ns demo
</code></pre>
<h2 id="heading-ui-component">🎨 UI Component</h2>
<p>This is the frontend web app that users see.</p>
<h3 id="heading-configmap-ui-configmapyaml">ConfigMap (<code>ui-configmap.yaml</code>)</h3>
<p>Stores the backend API URL:</p>
<pre><code class="lang-plaintext">apiVersion: v1
kind: ConfigMap
metadata:
  name: ui-config
data:
  API_URL: "http://bs:5000"
</code></pre>
<p>👉 <em>UI and BS are connected via environment URLs to make API requests.</em></p>
<h3 id="heading-deployment-ui-deploymentyaml">Deployment (<code>ui-deployment.yaml</code>)</h3>
<p>Runs the UI container:</p>
<pre><code class="lang-plaintext">apiVersion: apps/v1
kind: Deployment
metadata:
  name: ui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ui
  template:
    metadata:
      labels:
        app: ui
    spec:
      containers:
      - name: ui
        image: ghcr.io/benc-uk/k8s-demo-ui:latest
        ports:
        - containerPort: 80
        envFrom:
        - configMapRef:
            name: ui-config
</code></pre>
<p>The image already has the code and listens on port <strong>80</strong> (default HTTP).</p>
<h3 id="heading-service-ui-serviceyaml">Service (<code>ui-service.yaml</code>)</h3>
<p>Creates a stable DNS name:</p>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Service
metadata:
  name: ui
spec:
  selector:
    app: ui
  ports:
  - port: 80
    targetPort: 80
</code></pre>
<p>👉 <em>Pods have changing IPs. A Service acts like a permanent contact number (DNS) that always points to the right pod.</em></p>
<hr />
<h2 id="heading-business-service-bs">⚙️ Business Service (BS)</h2>
<p>This is the backend API that the UI calls.</p>
<h3 id="heading-configmap-bs-configmapyaml">ConfigMap (<code>bs-configmap.yaml</code>)</h3>
<pre><code class="lang-plaintext">apiVersion: v1
kind: ConfigMap
metadata:
  name: bs-config
data:
  DB_HOST: "db"
  DB_PORT: "5432"
  DB_NAME: "postgres"
  DB_USER: "postgres"
  DB_PASS: "postgres"
</code></pre>
<p>👉 <em>BS uses DB connection details via environment variables.</em></p>
<h3 id="heading-deployment-bs-deploymentyaml">Deployment (<code>bs-deployment.yaml</code>)</h3>
<pre><code class="lang-plaintext">apiVersion: apps/v1
kind: Deployment
metadata:
  name: bs
spec:
  replicas: 1
  selector:
    matchLabels:
      app: bs
  template:
    metadata:
      labels:
        app: bs
    spec:
      containers:
      - name: bs
        image: ghcr.io/benc-uk/k8s-demo-api:latest
        ports:
        - containerPort: 5000
        envFrom:
        - configMapRef:
            name: bs-config
</code></pre>
<p>👉 <em>Port 5000 is the BS app’s listening port.</em></p>
<h3 id="heading-service-bs-serviceyaml">Service (<code>bs-service.yaml</code>)</h3>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Service
metadata:
  name: bs
spec:
  selector:
    app: bs
  ports:
  - port: 5000
    targetPort: 5000
</code></pre>
<p>Now the UI can call <a target="_blank" href="http://bs:5000/api/"><code>http://bs:5000/api/</code></a><code>...</code> reliably.</p>
<hr />
<h2 id="heading-database-postgres">🗄 Database (Postgres)</h2>
<p>The storage layer of the app.</p>
<h3 id="heading-deployment-db-deploymentyaml">Deployment (<code>db-deployment.yaml</code>)</h3>
<pre><code class="lang-plaintext">apiVersion: apps/v1
kind: Deployment
metadata:
  name: db
spec:
  replicas: 1
  selector:
    matchLabels:
      app: db
  template:
    metadata:
      labels:
        app: db
    spec:
      containers:
      - name: db
        image: postgres:15
        ports:
        - containerPort: 5432
        env:
        - name: POSTGRES_PASSWORD
          value: postgres
        volumeMounts:
        - name: db-data
          mountPath: /var/lib/postgresql/data
      volumes:
      - name: db-data
        persistentVolumeClaim:
          claimName: db-pvc
</code></pre>
<p>👉 <em>5432 is the default PostgreSQL port.</em><br />👉 <em>/var/lib/postgresql/data is Postgres’s default data directory (set by the official image).</em></p>
<h3 id="heading-pvc-db-pvcyaml">PVC (<code>db-pvc.yaml</code>)</h3>
<pre><code class="lang-plaintext">apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: standard
</code></pre>
<p>👉 <em>PVC is just a YAML request; Kubernetes binds it to a PV (the real disk).</em></p>
<p>Now the DB data survives pod restarts ✅</p>
<h3 id="heading-service-db-serviceyaml">Service (<code>db-service.yaml</code>)</h3>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Service
metadata:
  name: db
spec:
  selector:
    app: db
  ports:
  - port: 5432
    targetPort: 5432
</code></pre>
<p>The BS connects to <code>db:5432</code>.</p>
<hr />
<h2 id="heading-ingress-ingressyaml">🌐 Ingress (<code>ingress.yaml</code>)</h2>
<p>Finally, I needed a way to reach the UI from my browser.</p>
<pre><code class="lang-plaintext">apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app
spec:
  rules:
  - host: app.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ui
            port:
              number: 80
</code></pre>
<p>👉 <em>Ingress is like a receptionist — it decides which internal Service should handle your request from outside.</em></p>
<hr />
<h2 id="heading-end-to-end-flow">🔄 End-to-End Flow</h2>
<p>When I open <a target="_blank" href="http://app.local:8080"><code>http://app.local:8080</code></a>, here’s what happens:</p>
<ol>
<li><p>Browser → request goes to <code>127.0.0.1:8080</code> with Host <code>app.local</code>.</p>
</li>
<li><p>Port-forward → tunnels to Ingress Service inside Minikube.</p>
</li>
<li><p>Ingress Controller (NGINX) sees host <code>app.local</code>, matches rule → sends to UI Service.</p>
</li>
<li><p>UI Service → forwards to UI Pod.</p>
</li>
<li><p>UI Pod → frontend makes API call <code>/api/health</code>.</p>
</li>
<li><p>Ingress → forwards to BS Service.</p>
</li>
<li><p>BS Service → forwards to BS Pod.</p>
</li>
<li><p>BS Pod → connects to DB Service (<code>db:5432</code>).</p>
</li>
<li><p>DB Pod → returns data → BS → UI → Browser.</p>
</li>
</ol>
<p>✅ All three tiers are talking inside Kubernetes.</p>
<h3 id="heading-diagram">📊 Diagram</h3>
<p>This picture helped me the most to understand the flow:</p>
<p><img src="https://global-uploads.webflow.com/64196dbe03e13c204de1b1c8/647745896562a7ecc4d1417c_73-image1.png" alt="Getting started with Kubernetes ingress - Spectro Cloud" /></p>
<hr />
<h2 id="heading-key-takeaways">📌 Key Takeaways</h2>
<ul>
<li><p><strong>Pods are temporary</strong> → use Services for stable connectivity.</p>
</li>
<li><p><strong>ConfigMaps</strong> → inject configs like API_URL or DB_HOST.</p>
</li>
<li><p><strong>Postgres defaults</strong> → port 5432, data at <code>/var/lib/postgresql/data</code>.</p>
</li>
<li><p><strong>PVCs</strong> → make DB data persistent across restarts.</p>
</li>
<li><p><strong>Ingress</strong> → routes external requests into cluster, like a receptionist.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">🎯 Conclusion</h2>
<p>This small hands-on activity cleared up a lot of my confusion as a fresher in DevOps.<br />Now I understand how UI, backend, and DB pods <strong>communicate inside Kubernetes</strong>, and how an Ingress routes external requests.</p>
<p>Next, I want to try writing <strong>Helm charts</strong> for these manifests and then explore <strong>ArgoCD GitOps</strong>.</p>
<p>If you’re also learning Kubernetes — I recommend setting up this three-tier demo. It’s the best way to actually see networking in action.</p>
]]></content:encoded></item></channel></rss>