Kubernetes Revision

Kubernetes is designed to orchestrate containers.

Why is Container Orchestration Needed?

Imagine you have:

  1. An application split into multiple services (e.g., frontend, backend, database), each running in its own container.

  2. Multiple instances of these containers to handle high traffic.

  3. A need to ensure these containers stay healthy and restart if they fail.

Managing this manually for dozens or hundreds of containers would be overwhelming. Container orchestration automates these tasks.

Example: Running a Web App with Kubernetes

Let’s say you have a web application with three components:

  1. Frontend (React or Angular)

  2. Backend API (Node.js, Python)

  3. Database (MySQL)

Without Orchestration:

  • You manually start containers for each service.

  • You restart failed containers yourself.

  • You update each container manually during a new release.

With Kubernetes:

  1. Define Your Application in a YAML File

  2. Deploy to Kubernetes:

  3. Kubernetes Handles the Rest

  • A cluster is a collection of machines (physical or virtual) working together to run applications using Kubernetes. It consists of one master node and multiple worker nodes. Think of it as a team: the master node is the manager, and the worker nodes are the employees doing the tasks.

Master Node Components

  1. API Server:

    • Significance: Acts as the central communication hub for the cluster.

    • Function:

      • Receives commands from users (kubectl or other tools).

      • Passes those instructions to the other components.

    • Example: When you type kubectl apply -f deployment.yaml, the API server processes this request and instructs the cluster to deploy your application.

  2. Scheduler:

    • Significance: Decides which worker node will run a specific task or application.

    • Function:

      • Analyzes the available resources on worker nodes (CPU, memory).

      • Places tasks on the most suitable node.

    • Example: If worker node 1 is busy, it assigns the job to worker node 2.

  3. etcd:

    • Significance: The brain's memory—a distributed key-value store.

    • Function:

      • Stores all the cluster’s state and configuration data.

      • Ensures consistency across the cluster.

    • Example: If a node fails, Kubernetes consults etcd to determine what was running there and reschedules it on another node.

  4. Controller Manager:

    • Significance: Handles the cluster's overall health and operations.

    • Function:

      • Manages controllers.

      • Examples of controllers:

        • Node Controller: Monitors worker nodes and replaces failed ones.

        • Replica Controller: Ensures the correct number of app instances are running.

    • Example: If 3 replicas of your app are required, but 1 crashes, the Controller Manager restarts it automatically.


Worker Node Components

  1. Kubelet:

    • Significance: The worker node's agent that follows orders from the master node.

    • Function:

      • Ensures the containers on the worker node are running as instructed by the master.

      • Reports the node's status back to the master.

    • Example: The Kubelet ensures the frontend container is running and will restart it if it crashes.

  2. Kube-proxy:

    • Significance: Manages networking for apps in the cluster.

    • Function:

      • Routes traffic to the right container or pod.

      • Allows communication between containers, worker nodes, and the outside world.

    • Example: If a user accesses your app, kube-proxy directs their request to the appropriate container.

  3. Container Runtime:

    • Significance: The software that runs your containers.

    • Function:

      • Responsible for starting, stopping, and managing the lifecycle of containers.

      • Examples: Docker, containerd.

    • Example: If your app's container is built with Docker, the runtime runs it on the worker node.


How They Work Together

  1. You issue a command: kubectl apply -f app-deployment.yaml.

  2. The API Server receives the request and updates the desired state in etcd.

  3. The Scheduler assigns the task to a suitable worker node.

  4. The Controller Manager ensures that the required number of app instances are running.

  5. On the worker node:

    • Kubelet ensures the assigned containers are running.

    • Kube-proxy routes network traffic to the correct containers.

    • The Container Runtime (e.g., Docker) runs the containers.

What is kubectl?

kubectl (pronounced cube-control) is a command-line tool used to interact with a Kubernetes cluster. It acts as the interface between the user and the Kubernetes API Server, allowing you to manage, monitor, and troubleshoot applications and resources in your cluster.

What is a Pod in Kubernetes?

A Pod is the smallest and most basic unit of deployment in Kubernetes. It represents a single instance of a running process in your cluster. It can run one or more containers and share the same resources.

How Kubernetes Helps with Scalability, Load Balancing, High Availability, Rollouts, and Rollbacks?

  • Scalability:

  • Adds or removes instances when needed. Example:

    1. Imagine you run an online store, and during a sale, many users visit your site.

    2. You start with 2 instances of your app. As traffic increases, Kubernetes automatically scales up to 10 instances.

    3. When traffic drops, it scales back down to save resources.

  • Load Balancing:

  • Spreads traffic evenly across instances. Example:

    1. Your app has 3 pods running.

    2. A user visits your site; Kubernetes sends their request to Pod 1.

    3. Another user visits; their request is routed to Pod 2, and so on.

  • High Availability:

  • Keeps your app running, even during failures. Example:

    1. You have 5 pods running your app.

    2. If one pod crashes, Kubernetes automatically creates a new pod to replace it.

    3. If a worker node fails, Kubernetes reschedules the pods to other nodes.

  • Rollouts:

  • Updates your app without downtime. Example:

    1. You release a new version of your app (v2).

    2. Kubernetes starts replacing the old pods (v1) with new ones (v2), one at a time.

    3. Users don’t experience downtime because the old pods keep running until the new ones are ready.

  • Rollbacks:

  • Reverts to a stable version if things go wrong. Example:

    1. Your new version (v2) has a bug.

    2. Kubernetes quickly rolls back to the previous version (v1).

    3. Users won’t notice because the rollback happens smoothly.

What is a Kubernetes Cluster?

A Kubernetes cluster is a group of computers (nodes) that work together to run and manage applications automatically. It has a control plane (brain) that makes decisions and worker nodes that run the applications.

Common Methods to Build a Kubernetes Cluster:

  1. Minikube – For local, single-node clusters (good for learning).

  2. Kubeadm – For setting up production-ready clusters manually.

  3. Cloud-managed services (EKS, AKS, GKE) – Fully managed Kubernetes in AWS, Azure, or Google Cloud.

  4. K3s – A lightweight Kubernetes version for small environments.

What is minikube?

  • A tool to run a Kubernetes cluster locally on your computer.

  • It's like a mini Kubernetes lab for testing and learning.

  • It sets up a small, single-node Kubernetes cluster on your machine.

  • It’s ideal for experimenting and development without needing a full-fledged cloud setup.

What is Kubeadm?

Kubeadm is a tool used to set up real Kubernetes clusters on actual servers.

Use Case:

  • If you want to set up a full Kubernetes cluster in the cloud or on physical/virtual machines.

  • Good for production or multi-node clusters (where you have multiple computers working together).

How it Works:

  • Helps you initialize a Kubernetes cluster on multiple machines.

  • Doesn't install extra tools like Minikube does—just the basic Kubernetes components.

  • Needs some manual setup, like configuring networking and joining worker nodes.

Key Differences :

FeatureMinikubeKubeadm
PurposeFor learning & testing (local or cloud)For setting up real Kubernetes clusters
Where it RunsOn a local PC/laptop, VM, or cloudOn cloud, physical, or VM servers
Cluster TypeSingle-node (by default) but can simulate multi-nodeSingle-node or multi-node (production-ready)
Ease of UseVery easy (one command setup)Requires manual setup and configuration
Extra FeaturesHas built-in Kubernetes tools & addons (e.g., dashboard)Only installs core Kubernetes, no extras

How Minikube Simulates Multi-Node Clusters ?

Minikube doesn’t create real separate nodes like a full Kubernetes cluster. Instead, it runs multiple worker nodes as separate containers or VMs within a single machine. This helps test multi-node behavior without needing multiple physical servers.

Example Command:

To start a Minikube cluster with 3 nodes (1 control plane + 2 worker nodes):

minikube start --nodes 3
  • Reality: All nodes run inside the same Minikube VM/container.

  • Limitation: Unlike a real multi-node Kubernetes setup, all nodes share the same underlying OS and resources.

Kubernetes Control Plane Ports and Their Purpose :

ProtocolDirectionPort RangePurposeUsed By
TCPInbound6443Kubernetes API server – the main entry point for cluster management requestsAll components interacting with the API server
TCPInbound2379-2380etcd server client API – responsible for storing the Kubernetes cluster statekube-apiserver, etcd
TCPInbound10250Kubelet API – enables the control plane to manage worker nodesControl plane, self
TCPInbound10259kube-scheduler – assigns pods to nodesSelf
TCPInbound10257kube-controller-manager – manages controllers that regulate cluster stateSelf

Note:

  • By default, etcd (which stores the cluster data) runs as part of the control plane and uses specific ports (2379-2380).

  • However, you can set up etcd on separate servers (outside the control plane) or change its port numbers if needed.

  • "Self" means that the component communicates with itself or is used internally within the same node.

    For example:

    • Kubelet API (10250): Used by the control plane to communicate with Kubelet, but Kubelet may also use it internally.

Kubernetes Worker Node Ports and Their Purpose

ProtocolDirectionPort RangePurposeUsed By
TCPInbound10250Kubelet API – enables the control plane to manage and monitor worker nodesControl plane, self
TCPInbound10256kube-proxy – manages network rules for Kubernetes servicesSelf, load balancers
TCPInbound30000-32767NodePort services – exposes Kubernetes services externally on worker nodesAll

Note:

  • The default port range for NodePort services is 30000-32767, but it can be customized.

  • Default port numbers can be changed, and if custom ports are used, those specific ports must be opened instead of the defaults listed here.

Why did we study about ports in detail above ?

  • Kubeadm requires manual setup, so understanding these ports is important when configuring firewalls, networking, and security rules.

  • Minikube, on the other hand, is an automated setup meant for local environments, and it handles these configurations internally.

  • However, if you're running Minikube in a custom setup (like a VM or cloud instance), knowing these ports can still be useful for troubleshooting or network access.

Now, let’s start our kubernetes cluster journey with minikube , since it’s much easier to setup as compared to kubeadm. Follow this guide to setup minikube : https://cloudvesna.com/step-by-step-guide-running-kubernetes-on-aws-ec2-with-minikube-3997d7aab6a4 .

Deployment of nginx for practicing Kubernetes :

At first , we create deployment ; then, we view the deployments and also the pods.

By default, Nginx listens on port 80 inside the container, but this port is inside the Pod's network namespace, not accessible directly from your local machine.

To make the Nginx service available outside the Pod, we can run the command :

kubectl expose deployment my-nginx --port=80 --type=LoadBalancer

  • This creates a Service in Kubernetes. A Service provides a stable network endpoint to access your Pods.

  • --port=80: Exposes the Pod's internal port 80 to the Service.

  • --type=LoadBalancer: Requests a cloud load balancer (or Minikube simulates one) to expose the Service externally.

Justification: A Service is necessary because Pods are ephemeral (they can restart or move to another node). A Service ensures a consistent way to access your Nginx app, regardless of where the Pod runs.

To check if the Service was created successfully, we can use the command : kubectl get services

This displays the list of Services, including:

  • ClusterIP: The internal IP assigned to the Service (accessible within the cluster).

  • External-IP: The external endpoint (if applicable).

  • Port: The port exposed by the Service.

Then we run the command minikube service my-nginx . Minikube translates the Kubernetes Service's external endpoint into a URL that you can access on your local machine. We can use minikube service my-nginx --url to obtain the accessible URL

On visiting the URL , through our local machine, we get :-

What is Minikube Dashboard?

Minikube Dashboard is a web-based user interface (UI) that allows you to visually interact with the resources running in your Minikube Kubernetes cluster. It provides a graphical view of various Kubernetes objects like Pods, Deployments, Services, ReplicaSets, and other components within your Minikube environment.

Demo WebApp Project :

At first, we will dockerize a simple react app by following the steps mentioned in my previous blog : https://iamkishaloy.hashnode.dev/docker-revision . Then we will build its image by a command like docker build -t kishaloy01/webapp-demo:02 . (since my Dockerhub username is kishaloy01). Then we will use docker login and enter our credentials properly ; then finally we will push the image like docker push kishaloy01/webapp-demo:02

Then we can use the command : kubectl create deployment webapp --image=IMAGEID (In my case, it was kubectl create deployment webapp --image=kishaloy01/webapp-demo:02 )

We can then check with get deployments and get pods commands :

We can then expose the PORT using service :

NOTE: We can also delete the undesirable deployments using the “delete” command.

For example :

NOTE: 1) The kubectl logs command is used to view the logs of a pod's container. It is helpful for debugging issues such as crashes, errors, or unexpected behavior within containers.

  1. The kubectl describe command provides a detailed overview of a resource (such as a pod, deployment, or service) in the cluster. It includes metadata, status, events, and other useful information that helps to debug problems and understand resource configurations.

Concept of Rollout in Kubernetes:

In Kubernetes, "rollout" refers to the process of updating a deployment to use a new version of an application or configuration. Kubernetes manages the rollout automatically to ensure that your application remains available during the update.

Let use see an example :

1. Create a Deployment

Let’s create a deployment with version 1 of the application.

kubectl create deployment my-app --image=nginx:1.20

Check the pods:

kubectl get pods

2. Update the Deployment

Now, update the application to a new version (nginx:1.21).

kubectl set image deployment/my-app nginx=nginx:1.21

3. Rollout Status

You can track the progress of the rollout with:

kubectl rollout status deployment/my-app

This shows whether the update was successful or if there are any issues.

After the update, new pods will run nginx:1.21, while the old ones are terminated.

4. Rollback if Needed

If the new version has issues, you can rollback to the previous version.

kubectl rollout undo deployment/my-app

This restores the previous version (nginx:1.20).

Rollout Benefits

  • Zero Downtime: Old pods are gradually replaced with new ones to ensure continuous availability.

  • Rollback: Quickly revert to a stable version if something goes wrong.

  • Control: Manage updates at your own pace using commands like pause and resume.

Rollback in Kubernetes

A rollback in Kubernetes reverts a deployment to a previous version if a newer version has issues like bugs, misconfiguration, or instability. Kubernetes maintains a history of revisions for each deployment, making it easy to switch back to an earlier version. Example: Point 4 above .

Self-Healing in Kubernetes

Self-healing in Kubernetes means the system automatically detects and fixes problems with your application to ensure it remains healthy and available. Kubernetes uses built-in mechanisms to monitor your application's state and restore it if something goes wrong.

Kubernetes monitors your application's desired state (defined in your deployment) and compares it to the actual state:

  1. Desired State: The state you want.

  2. Actual State: The state Kubernetes observes in the cluster.

If the actual state doesn't match the desired state (e.g., a pod crashes), Kubernetes automatically:

  • Restarts failed pods.

  • Reschedules pods on different nodes if a node fails.

  • Recreates pods if they are deleted accidentally.

Example : Self-Healing in Action :-

Step 1: Create a Deployment

Deploy an application with 3 replicas:

Check the pods:


Step 2: Simulate a Failure

Manually delete one of the pods:

Check the pods again:

  • What Happened? Kubernetes noticed one pod was missing (actual state ≠ desired state) and created a new pod to maintain 3 replicas. (Note: In the above example , we can see the AGEs of the pods to understand the phenomenon).

YAML Configuration for Deployment and Service in Kubernetes

In Kubernetes, YAML files are used to define configurations for deploying applications and exposing them as services. These configurations describe what Kubernetes should do and the desired state of your application. Using YAML configurations for Kubernetes deployments and services streamlines application management by making it simpler, consistent, and scalable. It allows developers and DevOps teams to focus on innovation rather than managing infrastructure manually.

Step 1: Deployment YAML

This file creates a deployment with 2 replicas of an Nginx application:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-nginx
  template:
    metadata:
      labels:
        app: my-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

Key Points:

  • replicas: 2: Runs 2 instances of the app.

  • selector: Matches pods with the app: my-nginx label.

  • containers:

    • image: nginx:latest: Pulls the Nginx image from Docker Hub.

    • containerPort: 80: Exposes port 80 inside the pod.

Step 2: Service YAML

This file exposes the pods created by the deployment:

apiVersion: v1
kind: Service
metadata:
  name: my-nginx-service
spec:
  selector:
    app: my-nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: LoadBalancer

Key Points:

  • selector: Matches pods with the app: my-nginx label.

  • ports:

    • port: 80: The port the service listens on.

    • targetPort: 80: The port the pods listen on.

  • type: LoadBalancer: Exposes the service to the internet.

How to Apply These Files

  1. Save the deployment YAML as deployment.yaml and the service YAML as service.yaml.

  2. Apply them using kubectl: kubectl get deployments and kubectl get services.

Note: We can see above : my-nginx-deployment and my-nginx-service

SDN-Based Networking:

SDN stands for Software-Defined Networking (SDN). SDN in Kubernetes separates networking from physical hardware and automates it. The networking part is managed using software.

Understanding SDN in Kubernetes:

Kubernetes follows a flat network model where:

  1. Every pod gets a unique IP address.

  2. Pods can communicate with each other as if they are on the same network.

  3. Services expose applications internally or externally without needing manual network setup.

This is achieved using Container Network Interface (CNI) plugins, which implement SDN in Kubernetes.

How SDN Works in Kubernetes :

1️⃣ Control Plane Handles Networking Rules

  • The Kubernetes API server and controllers manage networking rules.

  • These rules determine how pods communicate, how services are exposed, and how external users access apps.

2️⃣ SDN Implements the Rules

  • Instead of relying on physical routers/switches, SDN uses software to control traffic flow.

  • SDN tools like CNI plugins (Calico, Flannel, Cilium) implement these rules dynamically.

3️⃣ Network Policies Manage Traffic

  • Kubernetes uses Network Policies to define which pods/services can talk to each other.

  • For example, you can block database pods from being accessed by all other pods except the backend.

Different SDN Implementations in Kubernetes (CNI Plugins)

Kubernetes does not manage networking on its own. Instead, CNI (Container Network Interface) plugins handle SDN.

CNI PluginHow It WorksBest For
FlannelCreates a simple overlay networkEasy networking setup
CalicoUses BGP (Border Gateway Protocol) for direct routingPerformance & security
CiliumUses eBPF for faster networking {Extended Berkeley Packet Filter (eBPF)}Advanced networking policies
WeaveSimple & automatic networkingEasy multi-cluster networking

Analogy between AWS and Kubernetes :

AWS ComponentKubernetes EquivalentExplanation
EC2 InstancePodAn EC2 instance runs applications, just like a Kubernetes Pod runs one or more containers.
EBS (Elastic Block Store)Persistent Volume (PV)EBS provides persistent storage for EC2 instances, similar to how Persistent Volumes store data for Kubernetes pods.
ALB (Application Load Balancer)Service (LoadBalancer/ClusterIP/NodePort)ALB routes external traffic to EC2 instances, just like a Kubernetes Service routes traffic to Pods.
Route 53 (DNS Service)CoreDNSRoute 53 manages DNS for AWS resources, while CoreDNS provides internal DNS resolution in a Kubernetes cluster.

What is a Namespace in Kubernetes?

A Namespace is like a separate workspace inside a Kubernetes cluster.
It helps in organizing, isolating, and managing resources (pods, services, deployments, etc.).

Real-World Analogy:

  • Imagine a shopping mall .

  • Inside the mall, there are different stores (namespaces) like Electronics, Clothing, and Food.

  • Each store manages its own inventory (pods, services) without affecting others.

Why Use Namespaces?

Logical separation – Different teams/projects can work in different namespaces.
Resource isolation – You can limit CPU, memory, and storage per namespace.
Better security – Users can have access only to specific namespaces.
Easy management – Helps prevent naming conflicts (e.g., multiple nginx pods in different namespaces).

Default Namespaces in Kubernetes:

By default, Kubernetes has four namespaces:

NamespacePurpose
defaultUsed when no namespace is specified.
kube-systemUsed for Kubernetes internal components (e.g., scheduler, controller).
kube-publicReadable by everyone, used for cluster-wide information.
kube-node-leaseManages node heartbeat leases for health monitoring.

Creating a New Namespace

Method 1: Command Line

Create a namespace using:

kubectl create namespace my-namespace

Check existing namespaces:

kubectl get namespaces

Method 2: YAML File

apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace

Apply it using:

kubectl apply -f my-namespace.yaml

Deploying a Pod Inside a Namespace:

If you want to create a pod in my-namespace, modify the YAML:

apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
  namespace: my-namespace
spec:
  containers:
    - name: nginx-container
      image: nginx

Apply it:

kubectl apply -f my-nginx-pod.yaml

List pods inside the namespace:

kubectl get pods -n my-namespace

Deleting a Namespace (Caution!) :

To delete a namespace and everything inside it:

kubectl delete namespace my-namespace

This will remove all pods, services, and deployments inside my-namespace.

Some common Kubernetes errors :-

1. Err Image Pull

What is it?

  • Err Image Pull happens when Kubernetes (via the Kubelet on your worker nodes) is unable to pull (download) the container image for a Pod from a container registry (like Docker Hub, AWS ECR, Google Container Registry, etc.).

Why does this happen?

  • The most common reasons for this error are:

    • Incorrect image name: If the image name specified in your pod definition (YAML file) is wrong or misspelled, Kubernetes will fail to find and pull the image.

    • Wrong tag: If the image tag (version) specified doesn't exist in the registry, the pull will fail.

    • No access to the registry: If Kubernetes doesn't have permission to access the container registry (for example, using a private registry without proper credentials), it can't pull the image.

    • Network issues: Sometimes, the network connection between the Kubernetes node and the container registry is interrupted or has issues, preventing the image from being pulled.

How to Troubleshoot "Err Image Pull"?

  • Check the image name and tag: Ensure that the name of the image is correct and the tag (like nginx:latest) is valid.

  • Verify credentials: If the image is in a private registry, make sure Kubernetes has the right credentials. You can create a Kubernetes Secret to store the credentials and reference it in your deployment.

  • Check network: Ensure your nodes have internet access and can reach the registry.

2. CrashLoopBackOff

What is it?

  • CrashLoopBackOff is an error where a container inside a Pod continuously crashes and tries to restart over and over. Kubernetes will attempt to restart the container but if it keeps failing, it will eventually stop trying after several failed attempts, and the Pod enters a CrashLoopBackOff state.

Why does it happen?

  • Misconfigured application: The most common cause is that the application inside the container crashes due to a bug or misconfiguration. For example, an app might expect a file or environment variable that isn’t present, causing it to crash.

  • Out of memory or CPU: If the app uses more resources (like CPU or memory) than the node can provide, it might get killed by the operating system.

  • Incorrect command or entry point: If the command or entry point specified for the container is incorrect or the executable is missing, the container will crash.

  • Dependencies missing: The app might depend on other services or components that are not yet ready or are misconfigured.

How to Troubleshoot "CrashLoopBackOff"?

  • Check logs: Use kubectl logs <pod-name> to see the logs from the container and look for any errors that might indicate why the application is failing.

    This will show you any error messages output by the application inside the container.

  • Check resource usage: Ensure that the container has enough memory and CPU. If not, you can adjust the resource limits in your YAML file (like increasing memory limits).

  • Use kubectl describe pod: This can give more detailed information about the container's state and events that occurred, including whether the container was killed due to resource limits or crashed.

ReplicaSet:

What is a ReplicaSet?

A ReplicaSet is a Kubernetes controller that ensures a specific number of identical Pods are running in the cluster. If some Pods crash or get deleted, the ReplicaSet automatically replaces them.

Example in Kubernetes YAML :

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend-replicaset
spec:
  replicas: 3  # Ensure 3 frontend Pods exist
  selector:
    matchLabels:
      tier: frontend  # Find existing Pods with this label
  template:
    metadata:
      labels:
        tier: frontend  # New Pods will have this label
    spec:
      containers:
      - name: my-app
        image: nginx

How ReplicaSet Works Step by Step

Step 1️⃣: Searching for Pods with Label tier=frontend

When the ReplicaSet starts, it searches the entire cluster for existing Pods that have Label: tier=frontend (just like the manager checks which employees already have a "frontend" badge).

Step 2️⃣: Checking If These Pods Are Already Managed

  • If the found Pods are already managed by another controller (like a Deployment), the ReplicaSet ignores them.

  • If the Pods are NOT managed by anyone, the ReplicaSet takes control of them.

Step 3️⃣: Ensuring Exactly 3 Pods Exist

The ReplicaSet checks how many Pods it found with the label tier=frontend:
If 3 Pods are already there → Great! No action needed.
If only 2 Pods exist → The ReplicaSet creates 1 new Pod to reach the total of 3.
If 0 Pods exist → The ReplicaSet creates 3 new Pods to meet the requirement.

Checking in Kubernetes

1️⃣ Get all ReplicaSets

kubectl get rs

This shows how many Pods each ReplicaSet is managing.

2️⃣ Get all Pods

kubectl get pods --show-labels

This lists all Pods along with their labels.

Observations:

Naming Convention in Kubernetes:

Example

Consider this Deployment YAML file for an Nginx application:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest

What Happens When We Apply This?

When you run: kubectl apply -f deployment.yaml

We get :

Kubernetes creates:

  1. Deployment:

    • Name: nginx-deployment

    • This is the controller that ensures 3 Pods are always running.

  2. ReplicaSet:

    • Name: nginx-deployment-54c98b4f84

    • This is automatically created by the Deployment.

    • The hash (54c98b4f84) is based on the pod template and ensures uniqueness.

  3. Pods:

    • Names:

        nginx-deployment-54c98b4f84-j6rr5
        nginx-deployment-54c98b4f84-s6qfs   
        nginx-deployment-54c98b4f84-t6nt6
      

      Each Pod name consists of:

      <Deployment Name>-<ReplicaSet Hash>-<Unique Pod ID>

SUMMARY :

Kubernetes ObjectPurposeNaming ConventionExample
DeploymentEnsures a specified number of Pods are running and handles updates.<deployment-name>nginx-deployment
ReplicaSetEnsures the right number of Pods exist at all times. Created automatically by Deployment.<deployment-name>-<replicaset-hash>nginx-deployment-86dcfdf4c6
PodSmallest deployable unit in Kubernetes, containing a containerized app.<replicaset-name>-<unique-id>nginx-deployment-86dcfdf4c6-9d9mc

What Happens When You Update the Deployment?

Let's say you update the image in the Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20  # Updated from latest to 1.20

Run: kubectl apply -f deployment.yaml

What will happen?

  • A new ReplicaSet (e.g., nginx-deployment-75b9fd87c5) is created because the Pod template changed.

  • The old ReplicaSet (nginx-deployment-86dcfdf4c6) will be scaled down to 0 Pods.

  • The new ReplicaSet (nginx-deployment-75b9fd87c5) will create 3 new Pods.

Probes: Ensuring Application Health Inside Pods:

A Pod might be running, but the application inside it could be stuck, slow, or unresponsive.
To monitor application health inside the Pod, Kubernetes provides three types of probes:

1. Startup Probe: Checking If an App Has Started

  • Used only during application startup.

  • If the app takes a long time to start, Kubernetes waits until the app is ready instead of assuming it has failed.

  • Once the Startup Probe succeeds, it stops checking further.

🔵 Example of a Startup Probe in Kubernetes YAML:

apiVersion: v1
kind: Pod
metadata:
  name: slow-app
spec:
  containers:
  - name: slow-container
    image: myapp
    startupProbe:
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 10  # Wait 10 sec before first check
      periodSeconds: 5  # Check every 5 sec
      failureThreshold: 5  # Fail after 5 failed attempts
  • Here, Kubernetes waits 10 seconds before the first health check.

  • If the app starts slowly, Kubernetes waits longer before marking it as failed.

2. Readiness Probe: Checking If an App Is Ready to Receive Traffic

  • Used to decide when a Pod should receive traffic.

  • Even if the Pod is running, the app inside might not be ready yet.

  • If the Readiness Probe fails, Kubernetes removes the Pod from the load balancer until it recovers.

🔵 Example of a Readiness Probe in Kubernetes YAML:

apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  containers:
  - name: web-container
    image: mywebapp
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5  # Wait 5 sec before first check
      periodSeconds: 3  # Check every 3 sec
  • If the app inside isn’t ready, Kubernetes removes it from the load balancer.

  • Once it becomes ready, traffic resumes.

3. Liveness Probe: Checking If an App Is Still Alive

  • Used to check if an app has crashed or is stuck.

  • If the Liveness Probe fails, Kubernetes automatically restarts the Pod.

    🔵 Example of a Liveness Probe in Kubernetes YAML:

      apiVersion: v1
      kind: Pod
      metadata:
        name: backend-app
      spec:
        containers:
        - name: backend-container
          image: mybackend
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5  # Wait 5 sec before first check
            periodSeconds: 10  # Check every 10 sec
            failureThreshold: 3  # Restart Pod after 3 failures
    
    • If the app hangs or crashes, Kubernetes restarts the Pod.

Summary of Probes:

ComponentPurposeWhat It Checks?
Startup ProbeChecks if the application has startedIf the app takes too long to start
Readiness ProbeChecks if the app is ready to receive trafficIf the app is initialized and can serve requests
Liveness ProbeChecks if the app is still runningIf the app freezes or crashes

Microservice Traffic Flow in Kubernetes:

What is Microservice Traffic Flow?

Microservice traffic flow refers to how data moves between different microservices inside a Kubernetes cluster. { NOTE : Microservices in Kubernetes are a software development approach that breaks down an application into small, independent services. These services are then deployed using Kubernetes}.

1️⃣ How External Traffic Enters the Cluster

When a user opens a website (example.com)., the request goes through several steps:

🔹 Step 1: DNS Resolution

  • CoreDNS resolves example.com to an IP address, directing traffic to the right service.

🔹 Step 2: Traffic Reaches Kubernetes via Ingress or Load Balancer

  • Ingress Controller or Load Balancer routes traffic to the right microservice.

  • If the app is public, a Load Balancer (AWS ELB, Azure LB, etc.) is used.

  • If it’s inside Kubernetes, Ingress handles routing.

Ingress Example (Routes traffic based on URL):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ecommerce-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /shop
        backend:
          service:
            name: shop-service
            port:
              number: 80
      - path: /cart
        backend:
          service:
            name: cart-service
            port:
              number: 80

🔹 Step 3: Service Routes Traffic to the Correct Pod

Since Pods have dynamic IPs, a Kubernetes Service gives them a stable IP.

Types of Services:

  1. ClusterIP – Default, used for internal traffic.

  2. NodePort – Exposes a service on a specific port.

  3. LoadBalancer – Exposes a service externally.

Service Example (Routes traffic to the correct microservice):

apiVersion: v1
kind: Service
metadata:
  name: shop-service
spec:
  selector:
    app: shop
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP

The service ensures requests reach the correct Pods, even if their IPs change.


2️⃣ How Microservices Communicate Internally

Once inside Kubernetes, microservices often need to communicate with each other.

🔹 Scenario: Checkout Service Needs Product Details

  • The checkout-service needs to call inventory-service to check stock.

  • DNS-Based Service Discovery happens using service-name.namespace.svc.cluster.local.

  • Example: curl http://inventory-service.default.svc.cluster.local:80

  • The checkout-service can call the inventory-service using the internal ClusterIP.


3️⃣ Securing Microservice Traffic

To ensure safe and controlled communication, Kubernetes provides:

Security FeaturePurposeExample
Network PoliciesRestrict which Pods can talk to each otherFirewalls inside a mall, allowing only certain employees to enter restricted areas
Service Mesh (Istio, Linkerd)Adds encryption, retries, monitoring to trafficMall security cameras tracking visitor movement
TLS Encryption (mTLS)Encrypts traffic between servicesA secure vault in a bank

Example: Network Policy (Only Allows Checkout to Call Inventory)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-checkout-to-inventory
spec:
  podSelector:
    matchLabels:
      app: inventory
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: checkout
  • This ensures that only checkout-service can talk to inventory-service, blocking unauthorized services.

DaemonSet in Kubernetes:

What is a DaemonSet?

A DaemonSet ensures that a specific Pod runs on every node in a Kubernetes cluster.

🔹 Why Do We Need DaemonSets?

Some system-level services should run on all nodes, such as:
Log collectors (e.g., Fluentd, Filebeat) – To collect logs from all nodes.
Monitoring agents (e.g., Prometheus Node Exporter) – To track node performance.
Security tools (e.g., Falco) – To monitor system activity for security threats.

Think of it like:
If Kubernetes is a city, a DaemonSet is like having a security guard at every building instead of just one main security office.


🔹 How Does a DaemonSet Work?

  • It automatically creates a Pod on every node.

  • When a new node is added, it adds a Pod on that node.

  • If a node is removed, the Pod on that node is deleted.


Example: Running a Log Collector on Every Node

Imagine you have a Kubernetes cluster with three nodes, and you need Fluentd to collect logs from all nodes.

DaemonSet YAML to Deploy Fluentd on All Nodes

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-daemonset
  labels:
    app: fluentd
spec:
  selector:
    matchLabels:
      name: fluentd-pod
  template:
    metadata:
      labels:
        name: fluentd-pod
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd:v1.14
        resources:
          limits:
            memory: 200Mi
            cpu: 100m
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

What This Does:

  • Creates a Fluentd Pod on every node.

  • Mounts /var/log to collect logs from all nodes.

  • Automatically runs on new nodes if added to the cluster.

Apply the DaemonSet in Kubernetes

kubectl apply -f fluentd-daemonset.yaml

Check DaemonSet Status

kubectl get daemonset

Output:

NAME               DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
fluentd-daemonset   3         3         3       3            3           <none>          10s

Means: Fluentd is running on all three nodes in the cluster.

🔹 Controlling Where DaemonSet Runs

By default, a DaemonSet runs on all nodes, but you can limit it to specific nodes using nodeSelector or nodeAffinity.

Example: Run DaemonSet Only on Worker Nodes

spec:
  template:
    spec:
      nodeSelector:
        node-role.kubernetes.io/worker: "true"

This ensures Fluentd runs only on worker nodes and not on master nodes.

Quick Hands-On Commands :

Check All DaemonSets

kubectl get daemonsets -A

Describe DaemonSet Details

kubectl describe daemonset fluentd-daemonset

Delete DaemonSet

kubectl delete daemonset fluentd-daemonset

Kubernetes StatefulSet:

Unlike Deployments, where Pods are identical and can be replaced freely, StatefulSet Pods have:
Fixed names (e.g., pod-0, pod-1, pod-2)
Persistent storage that does not get deleted when a Pod restarts
Ordered scaling (Pods start and stop in a defined sequence)

Think of it like:
A hotel where every room (Pod) has a fixed room number, and when a guest leaves, their room and belongings (Persistent Volume) are still reserved for them.

How StatefulSet Works:

1️⃣ Creates Pods with unique, ordered names (pod-0, pod-1, etc.)
2️⃣ Ensures stable network identities using a Headless Service (pod-0.app, pod-1.app)
3️⃣ Uses Persistent Volumes so data is not lost when a Pod restarts
4️⃣ Maintains order when scaling up/down (adds/removes Pods in sequence)

Example: Deploying MySQL with StatefulSet:

✅ Step 1: Create a Headless Service

A Headless Service gives each StatefulSet Pod a fixed DNS name.

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  clusterIP: None  # Makes it headless
  selector:
    app: mysql
  ports:
    - port: 3306

📌 Why Headless? Because each Pod needs a stable hostname (e.g., mysql-0, mysql-1).


✅ Step 2: Create the StatefulSet for MySQL

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql  # Uses the Headless Service
  replicas: 3  # Three MySQL Pods
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "mypassword"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

What This Does:
✅ Creates 3 MySQL Pods (mysql-0, mysql-1, mysql-2)
✅ Uses Persistent Volumes (mysql-data) so data persists after restarts
✅ Ensures each Pod has a fixed hostname (mysql-0.mysql, mysql-1.mysql)


✅ Step 3: Deploy the StatefulSet and the service :

✅ Step 4: Check StatefulSet Status:

Hence, all 3 MySQL Pods are running.

Check Persistent Volume Claims (PVC)

kubectl get pvc

Each Pod gets its own separate storage (mysql-data-mysql-0, mysql-data-mysql-1).

Scale Up StatefulSet to 5 Pods

kubectl scale statefulset mysql --replicas=5

Scale Down StatefulSet to 2 Pods

kubectl scale statefulset mysql --replicas=2

📌 Note: When scaling down, the last Pod is removed first (mysql-2 before mysql-1).

Quick Hands-On Commands:

Check All StatefulSets

kubectl get statefulsets -A

Describe StatefulSet Details

kubectl describe statefulset mysql

Delete StatefulSet (But Keep Storage)

kubectl delete statefulset mysql --cascade=orphan

Delete StatefulSet (And Remove Storage)

kubectl delete statefulset mysql
kubectl delete pvc -l app=mysql

Init Containers:

What are Init Containers?

Init containers are special containers that run before the main container in a Pod. They are used for preparing environments before the actual application starts.

Why use Init Containers?

  • Preload data (e.g., fetch database schema).

  • Wait for dependencies (e.g., ensure the database is running before starting the app).

  • Set up configurations dynamically.

Practical: Using an Init Container

Create a file pod-with-init.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: init-demo
spec:
  initContainers:
    - name: init-container
      image: busybox
      command: ['sh', '-c', 'echo "Initializing..."; sleep 5; echo "Done!"']
  containers:
    - name: main-container
      image: nginx
      command: ['sh', '-c', 'echo "Main container started"; sleep 3600']

🔹 Apply and Check

kubectl apply -f pod-with-init.yaml
kubectl get pods
kubectl describe pod init-demo

You will see that init-container runs first before the main container starts.

Resource Requests:

What are Resource Requests?

Resource requests in Kubernetes tell the scheduler how much CPU and memory a container needs at a minimum.

Why use Resource Requests?

  • Ensures a Pod gets at least the requested resources.

  • Helps Kubernetes schedule Pods efficiently.

Practical : Setting Resource Requests

Create a file pod-resource-request.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: resource-pod
spec:
  containers:
    - name: app-container
      image: nginx
      resources:
        requests:
          memory: "256Mi"  # Minimum memory required
          cpu: "250m"       # Minimum CPU required (250 millicores = 0.25 CPU)

Apply and Check

kubectl apply -f pod-resource-request.yaml
kubectl describe pod resource-pod

Kubernetes LimitRange:

What is LimitRange?

A LimitRange sets the minimum and maximum amount of CPU/memory a container can request in a namespace.

Why use LimitRange?

  • Prevents any container from consuming too many resources.

  • Ensures fair resource distribution.

Practical: Setting LimitRange

Create a file limit-range.yaml:

apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-mem-limits
spec:
  limits:
    - default:
        memory: 512Mi
        cpu: "500m"
      defaultRequest:
        memory: 128Mi
        cpu: "250m"
      type: Container

Apply and Check:

kubectl apply -f limit-range.yaml
kubectl get limitrange
kubectl describe limitrange cpu-mem-limits

Now, if a Pod does not specify its resource limits, Kubernetes will apply these defaults.

Observation:

Kubernetes Resource Quota:

What is a Resource Quota?

A Resource Quota restricts how much total CPU/memory/storage a namespace can consume.

Why use Resource Quota?

  • Prevents one team from consuming all cluster resources.

  • Ensures fair allocation across multiple teams.

Practical : Setting a Resource Quota

Create a file resource-quota.yaml:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: my-quota
spec:
  hard:
    pods: "10"              # Maximum 10 Pods in this namespace
    requests.cpu: "2"       # Max 2 CPU cores requested
    requests.memory: "4Gi"  # Max 4GB memory requested
    limits.cpu: "4"         # Max 4 CPU cores allowed
    limits.memory: "8Gi"    # Max 8GB memory allowed

Apply and Check

kubectl apply -f resource-quota.yaml
kubectl get resourcequota
kubectl describe resourcequota my-quota

Now, if someone tries to create more than 10 Pods, Kubernetes will block the request.

Multi-Container Pod in Kubernetes:

What is a Multi-Container Pod?

A Multi-Container Pod is a Kubernetes pod that contains more than one container. These containers share the same network (IP), storage (volumes), and lifecycle, allowing them to work together.

Why Use Multi-Container Pods?

  • One container helps another (e.g., logging, monitoring).

  • One container transforms data for another.

  • Acts as a proxy between services.

Example:

Imagine a food delivery app:

  • Main Container: Runs the app that processes orders (order-service).

  • Sidecar Container: A separate container collects logs (logging-service).

Multi-Container Pod Example:

apiVersion: v1
kind: Pod
metadata:
  name: multi-container-pod
spec:
  containers:
  - name: order-service
    image: nginx  # Main container
  - name: logging-service
    image: busybox
    command: ["sh", "-c", "while true; do echo 'Logging Order Data'; sleep 5; done"]

How to Apply & Test

kubectl apply -f multi-container-pod.yaml
kubectl logs multi-container-pod -c logging-service  # View logs of the sidecar container

Outcomes:

Kubernetes ConfigMap:

What is a ConfigMap?

A ConfigMap in Kubernetes is used to store configuration data separately from the application code. This helps in keeping the application flexible and easier to manage.

Think of ConfigMap as a settings file (like .env in local development) that stores configuration details such as:

  • Database connection details

  • API keys (non-sensitive)

  • Environment-specific settings

Why Use ConfigMap?

Instead of hardcoding configurations inside your application, you can store them in a ConfigMap.

❌ Without ConfigMap (Hardcoded)

env:
  - name: DATABASE_URL
    value: "mysql://user:password@db-host:3306/mydb"
  • Problem: If the database host or password changes, you need to modify and redeploy the application.

✅ With ConfigMap

envFrom:
  - configMapRef:
      name: my-config
  • Advantage: If the database URL changes, you only update the ConfigMap without redeploying the application.

NOTE: A ConfigMap stores configuration data (key-value pairs) that can be injected into pods without changing the container image*.*

Create ConfigMap from YAML:

Let's define a ConfigMap named app-config with some database settings.

🔹 ConfigMap YAML File

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: "mysql"
  DATABASE_PORT: "3306"
  APP_ENV: "production"

🔹 Apply the ConfigMap

kubectl apply -f app-config.yaml

🔹 Verify the ConfigMap

kubectl get configmap app-config -o yaml

Outcomes:

Using ConfigMap as Environment Variables:

Now, let's use our app-config ConfigMap inside a Pod.

🔹 Define a Pod using ConfigMap

apiVersion: v1
kind: Pod
metadata:
  name: configmap-pod
spec:
  containers:
  - name: app-container
    image: nginx
    envFrom:
    - configMapRef:
        name: app-config  # Inject ConfigMap as environment variables

🔹 Apply the Pod

kubectl apply -f configmap-pod.yaml

🔹 Check if ConfigMap values are available in the container

kubectl exec -it configmap-pod -- env | grep DATABASE_

Expected Output:

DATABASE_HOST=mysql
DATABASE_PORT=3306

Outcomes:

Summary:

✅ ConfigMaps store configuration separately from application code.
✅ They can be used as environment variables or mounted as files in a Pod.
✅ Updating a ConfigMap does not require redeploying the Pod.

Short Summary:

ConceptDescription
Pod ControllerReplicationEnsures the specified number of Pod replicas are running at all times.
ReplicaSetManages the lifecycle of Pods, ensuring the desired number of replicas is maintained. A ReplicaSet is used by Deployments.
DeploymentManages stateless applications by creating and updating Pods in a controlled manner, ensuring the desired state.
DaemonSetEnsures that a copy of a Pod is running on each node (or a subset of nodes) in a Kubernetes cluster, often used for logging, monitoring, or networking.
StatefulSetManages stateful applications, ensuring each Pod has a stable, unique identity (e.g., database Pods).
ServiceClusterIPExposes the service on an internal IP within the cluster, only accessible within the cluster.
HeadlessA service with no ClusterIP, used to directly access the Pods via DNS records, typically used with StatefulSets.
NodePortExposes the service on a specific port on each node in the cluster, making it accessible externally at <NodeIP>:<NodePort>.
LoadBalancerExposes the service to external traffic using a cloud provider's load balancer, automatically provisioning an external IP.
ExternalNameMaps the service to a DNS name, allowing access to external services by their name, instead of IP or hostname.

Ingress Controller:

What is an Ingress Controller?

An Ingress Controller is a component in Kubernetes (K8s) that manages ingress resources. It acts as a traffic manager or gatekeeper for HTTP and HTTPS traffic that comes into your Kubernetes cluster. Its main job is to route the external HTTP/HTTPS requests to the appropriate services inside the Kubernetes cluster.

How does it work?

  1. Ingress Resource: This is a set of rules or configurations that define how the HTTP(S) requests should be routed to different services in your Kubernetes cluster.

  2. Ingress Controller: It reads these rules (ingress resources) and configures the system to manage incoming traffic accordingly.

Key Concepts

  1. Ingress Resource: Defines the rules for routing HTTP/HTTPS traffic. It can specify things like:

    • Which URLs map to which services

    • Whether or not to use SSL (HTTPS)

    • Path-based routing (e.g., /app1 goes to service A, /app2 goes to service B)

  2. Ingress Controller: It's like a proxy that reads the ingress resource and makes sure the traffic is forwarded correctly to the services.

Practical Example

Let’s say we have two applications running in our Kubernetes cluster:

  • App1 (running on port 8081)

  • App2 (running on port 8082)

Step 1: Create an Ingress Resource

We define an Ingress resource to tell Kubernetes how traffic should be routed. For example, we could say:

Here’s an example of an Ingress Resource configuration:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  namespace: default
spec:
  rules:
  - host: mywebsite.com
    http:
      paths:
      - path: /app1
        pathType: Prefix
        backend:
          service:
            name: app1-service
            port:
              number: 8081
      - path: /app2
        pathType: Prefix
        backend:
          service:
            name: app2-service
            port:
              number: 8082

This resource defines that:

  • Requests to /app1 will be sent to app1-service on port 8081.

  • Requests to /app2 will be sent to app2-service on port 8082.

Step 2: Install and Configure the Ingress Controller

To manage these ingress resources, we need to install an Ingress Controller (like NGINX Ingress Controller). This controller will listen for incoming requests and apply the routing rules defined in the Ingress resource.

You can install NGINX Ingress Controller using Kubernetes commands, for example:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

Once the Ingress Controller is installed and running, it automatically starts managing incoming HTTP/HTTPS traffic based on the ingress rules you’ve defined.

Step 3: Accessing Your Applications

Now, let's assume your DNS is set up to route mywebsite.com to your Kubernetes cluster's external IP. When someone accesses http://mywebsite.com/app1, the Ingress Controller will route this traffic to the app1-service running on port 8081. Similarly, http://mywebsite.com/app2 will be routed to the app2-service.

Why is it Useful?

  • Centralized Traffic Management: Instead of creating a separate load balancer for each service, you can have a single point (Ingress Controller) for managing all external traffic.

  • Simplified URL Routing: With path-based routing, you can easily manage different apps within the same domain (mywebsite.com/app1, mywebsite.com/app2).

  • SSL Termination: Ingress controllers can handle HTTPS and SSL termination, meaning they can manage the secure connection between external users and your services.

  • Cost-Efficient: Using an Ingress Controller reduces the need for multiple load balancers, saving costs.

Pod Autoscaling:

What is Pod Autoscaling?

In Kubernetes, a Pod is the smallest deployable unit. It represents a single instance of a running process in a cluster. Pod Autoscaling refers to the ability to automatically adjust the number of Pods running in a Kubernetes deployment based on the current demand or load. This helps ensure your application remains responsive and efficient, whether it's experiencing high traffic or low traffic.

Why do we need Pod Autoscaling?

  1. Efficient Resource Management: Instead of manually scaling the number of Pods based on expected load, Kubernetes can automatically increase or decrease Pods as needed.

  2. Cost Efficiency: Autoscaling ensures that you’re only running the number of Pods necessary at any given moment, which helps save resources (and costs) when the demand is low.

  3. Performance Optimization: It ensures that your app can handle increased traffic by scaling up automatically when the load is high.

How does Pod Autoscaling work?

There are two primary types of Pod Autoscaling in Kubernetes:

  1. Horizontal Pod Autoscaler (HPA): This automatically adjusts the number of Pods based on CPU or memory usage or other custom metrics.

  2. Vertical Pod Autoscaler (VPA): This automatically adjusts the CPU and memory resources allocated to a Pod based on its usage.

However, in this explanation, we’ll focus mainly on Horizontal Pod Autoscaler (HPA) because it’s the most common one used.

Key Concepts of Horizontal Pod Autoscaler (HPA):

  1. Metrics: The HPA uses metrics like CPU usage and memory usage to determine whether a Pod needs to be scaled up or down. For example, if CPU usage goes beyond 80% for a period, the HPA will create more Pods to handle the extra load.

  2. Target Utilization: You set a target utilization value (like 50% CPU). The HPA will try to maintain the target CPU or memory usage by scaling the number of Pods.

  3. Scaling Decision: If the current load exceeds the target utilization, HPA scales up (adds more Pods). If the load is less, it scales down (removes Pods).

How to Set Up Horizontal Pod Autoscaling?

Here’s a simple example to help you understand how it works in practice.

Step 1: Deploy Your Application

First, let’s say you have a simple web application running in a Kubernetes deployment with a single Pod.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1  # Initially we have one Pod
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: my-app-image
        resources:
          requests:
            cpu: "100m"  # CPU request (in milliCPU)
            memory: "128Mi"
          limits:
            cpu: "500m"  # CPU limit
            memory: "512Mi"

Step 2: Create an HPA Resource

Now, we define the Horizontal Pod Autoscaler. This will automatically scale the number of Pods based on the average CPU usage. We’ll set a target of 50% CPU utilization. If the average CPU usage of the Pods exceeds 50%, it will scale up the Pods, and if the usage falls below that threshold, it will scale down.

Here’s an example of the HPA resource:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 1  # Minimum number of Pods
  maxReplicas: 5  # Maximum number of Pods
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50  # Target 50% CPU usage

Step 3: How the Autoscaler Works

  • Scaling Up: If the average CPU usage exceeds 50% for a sustained period, Kubernetes will add more Pods to handle the load. So if the load increases and the current Pod(s) are overworked, the system will automatically add new Pods.

  • Scaling Down: If the CPU usage falls below the 50% target for a sustained period, the HPA will scale down by removing excess Pods. For example, if the load decreases, the system might reduce the number of Pods from 3 to 1.

Step 4: Monitor the Autoscaling

To check the status of the HPA and see how many Pods are currently running, you can use the following command:

kubectl get hpa

This will show you something like this:

NAME        REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
my-app-hpa  Deployment/my-app  50%/50%   1         5         3         5m

In this example, it shows that:

  • Target is 50% CPU utilization.

  • Current replicas is 3 (out of a possible 1–5).

  • The HPA is adjusting the replicas based on CPU usage.

Concept of Taint & Toleration in Kubernetes :

In Kubernetes, Taint & Toleration is a mechanism used to control which Pods can be scheduled on which Nodes. It helps in restricting or prioritizing certain workloads to specific nodes.

What is a Taint?

A Taint is a label (restriction) applied to a Node that prevents general Pods from being scheduled on it. A Node with a Taint will only allow Pods that have the matching Toleration.

Syntax of a Taint:

kubectl taint nodes <node-name> key=value:effect
  • key=value → The identifier for the taint

  • effect → Defines how the taint behaves (explained below)

Types of Effects:

  1. NoSchedule → Prevents scheduling new Pods unless they have a matching toleration.

  2. PreferNoSchedule → Tries to avoid scheduling Pods but does not strictly enforce it.

  3. NoExecute → Evicts already running Pods that don’t tolerate the taint.

What is a Toleration?

Think of it as a "PASS CARD" that lets a Pod enter a restricted Node.

Syntax of a Toleration in a Pod's YAML:

tolerations:
- key: "key"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"
  • The Pod will be scheduled on the Node only if the Taint and Toleration match.

PRACTICAL:

Scenario 1: Dedicated Nodes for Critical Applications

Imagine you have a Kubernetes cluster with 5 Nodes, and one of them has high-end hardware. You want only critical workloads (like a database) to run on that Node.

Step 1: Apply a Taint to the High-End Node

kubectl taint nodes high-performance-node critical=true:NoSchedule

This prevents all normal Pods from being scheduled on this node.

Step 2: Add a Toleration to the Critical Workload

Modify the Pod definition for your database:

apiVersion: v1
kind: Pod
metadata:
  name: critical-db
spec:
  tolerations:
  - key: "critical"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"

Now, only the critical-db Pod can be scheduled on high-performance-node, while other Pods are kept away.

Scenario 2: Temporary Maintenance on a Node

You have a Node node1 that needs maintenance, and you want to evict running Pods from it.

Step 1: Apply a Taint to Evict Pods

kubectl taint nodes node1 maintenance=true:NoExecute

All Pods without a toleration for this taint will be removed from this Node.

Step 2: Allow Certain Pods to Stay

If you want some system Pods (like monitoring agents) to continue running, you add a toleration:

tolerations:
- key: "maintenance"
  operator: "Equal"
  value: "true"
  effect: "NoExecute"

Now, only these Pods will stay, while others will be evicted.

Real-world analogy: VIP lounge (tainted Node) only allows VIP guests (Pods with matching toleration).

What is a Static Pod?

Definition:

A Static Pod is a special type of Pod that is directly managed by the Kubelet on a specific Node, not by the Kubernetes API Server.

Key Characteristics:

  • They do not have a ReplicaSet or Deployment.

  • They are not managed by the Kubernetes Scheduler.

  • They run only on the node where they are defined.

  • If the Node crashes, the Pod will not restart on another Node automatically.

Analogy:

Think of Static Pods like system services (e.g., SSH, Nginx, or a database) installed directly on a machine. These services always run on that specific machine, regardless of external systems.


Example: Running a Static Pod

Step 1: Create a Static Pod YAML on a Node

A Static Pod is created by placing a YAML file in the /etc/kubernetes/manifests/ directory on a Node.

apiVersion: v1
kind: Pod
metadata:
  name: static-web
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80

Step 2: Move the YAML to the Static Pod Directory

mv static-pod.yaml /etc/kubernetes/manifests/

Step 3: Verify the Pod is Running

kubectl get pods -A

Since the Static Pod is not controlled by the API Server, it won't appear in kubectl get deployments, but you can still see it in the pod list.

What is nodeName in Kubernetes?

Definition:

nodeName is a hardcoded way to schedule a Pod on a specific Node.

Key Characteristics:

  • The Pod is only scheduled on the Node specified.

  • If the Node is unavailable, the Pod is stuck in Pending state.

  • No failover to another Node unless re-created.

Analogy:

Think of nodeName like manually assigning a delivery to a specific worker. If that worker is unavailable, the delivery doesn’t happen.

Example: Assigning a Pod to a Specific Node

Step 1: Get the Node Name

kubectl get nodes

Example output:

NAME         STATUS   ROLES    AGE     VERSION
node-1       Ready    worker   10d     v1.24.0
node-2       Ready    worker   10d     v1.24.0

Step 2: Create a Pod YAML with nodeName

apiVersion: v1
kind: Pod
metadata:
  name: nginx-node1
spec:
  nodeName: node-1
  containers:
  - name: nginx
    image: nginx

Step 3: Apply the YAML

kubectl apply -f nginx-node1.yaml

Step 4: Verify the Pod is Running on the Specific Node

kubectl get pods -o wide

If node-1 is unavailable, the Pod will be stuck in Pending state.

What is NodeAffinity?

Definition:

NodeAffinity is a mechanism in Kubernetes that allows you to control how Pods are scheduled onto Nodes based on specific conditions.

It works like an advanced version of nodeName, where instead of hardcoding a specific Node, we define rules for selecting the Node dynamically.


Key Characteristics:

  • Unlike nodeName, it allows flexible Node selection.

  • Works with Labels assigned to Nodes.

  • Helps in distributing workloads across Nodes based on their characteristics (e.g., CPU, memory, region).


Analogy:

Think of NodeAffinity like assigning students to classrooms based on their subjects.

  • A Math student should be in a Math classroom.

  • A Science student should be in a Science classroom.

Here, the subject is like a Node label, and the student is the Pod.


Example: Using NodeAffinity

Step 1: Label Nodes Based on Region

First, find available Nodes:

kubectl get nodes

Example output:

NAME          STATUS   ROLES    AGE     VERSION
node-1        Ready    worker   100d    v1.24.0
node-2        Ready    worker   100d    v1.24.0

Now, assign labels:

kubectl label nodes node-1 region=us-east
kubectl label nodes node-2 region=us-west

Step 2: Define a Pod with NodeAffinity

apiVersion: v1
kind: Pod
metadata:
  name: nginx-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: region
            operator: In
            values:
            - us-east
  containers:
  - name: nginx
    image: nginx

Step 3: Apply the YAML

kubectl apply -f nginx-affinity.yaml

Step 4: Verify if the Pod is Scheduled on the Correct Node

kubectl get pods -o wide

If everything is correct, the Pod should be running on node-1 (us-east).


Types of NodeAffinity:

TypeDescription
requiredDuringSchedulingIgnoredDuringExecutionStrict rule - The Pod will only schedule on matching Nodes.
preferredDuringSchedulingIgnoredDuringExecutionSoft rule - The Pod prefers a matching Node but will run elsewhere if needed.

NOTE:

ConceptDescriptionAnalogy
ETCDStores all cluster dataA digital notebook where Kubernetes writes all cluster details
ETCD BackupSaves a snapshot of the clusterTaking a backup of your phone data
ETCD RestoreRecovers the cluster from backupRestoring phone data after a reset

Kubernetes LocalPath Storage:

LocalPath Storage in Kubernetes allows you to use a node's local disk storage to store data for your applications. It is commonly used for testing, development, and single-node clusters.

What is LocalPath Storage?

LocalPath Storage is provided by Rancher’s Local Path Provisioner, which dynamically creates PersistentVolumes (PVs) using local storage on the worker node where a Pod runs.

Think of it like this:

  • If your application needs storage, LocalPath will allocate a folder on the node’s local disk and mount it to your Pod.

  • The data will not move if the Pod is scheduled on another node (unlike cloud-based storage like EBS or NFS).


When to Use LocalPath Storage?

For development & testing – Quick and easy storage setup.
For single-node Kubernetes clusters – No need for external storage.
For lightweight applications – When you don’t need persistent cloud storage.

🚫 When NOT to use it:

  • In production multi-node clusters (data won’t move with the Pod).

  • When you need high availability (node failure = data loss).

  • For distributed applications that require shared storage.


How Does LocalPath Storage Work?

1️⃣ Local Path Provisioner creates a folder on the node.
2️⃣ It mounts that folder into your Pod.
3️⃣ The Pod reads/writes data to that folder.
4️⃣ If the Pod moves to another node, the data does NOT follow it.

Example: Running a MySQL Database with LocalPath Storage

1️⃣ Install Local Path Provisioner

If you're using Rancher Desktop or k3s, LocalPath is pre-installed.
Otherwise, install it manually:

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml

Verify installation:

kubectl get storageclass

You should see:


2️⃣ Create a PersistentVolumeClaim (PVC)

This requests storage from LocalPath.

Create a file mysql-pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce  # Only one Pod can use it at a time
  resources:
    requests:
      storage: 1Gi
  storageClassName: local-path

Apply it:

kubectl apply -f mysql-pvc.yaml

Check PVC status:

kubectl get pvc

Output:


3️⃣ Deploy MySQL with LocalPath Storage

Create a file mysql-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:5.7
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "password123"
          volumeMounts:
            - mountPath: /var/lib/mysql
              name: mysql-storage
      volumes:
        - name: mysql-storage
          persistentVolumeClaim:
            claimName: mysql-pvc

Apply it:

kubectl apply -f mysql-deployment.yaml

Check pod and storage:

kubectl get pods -o wide
kubectl describe pod <pod_name>

4️⃣ Verify Data Persistence

Now, let’s test if the data is stored locally:

🔹 Step 1: Connect to MySQL Pod

kubectl exec -it $(kubectl get pods -l app=mysql -o jsonpath="{.items[0].metadata.name}") -- mysql -u root -p

Enter password: password123

🔹 Step 2: Create a Test Database

CREATE DATABASE testdb;
SHOW DATABASES;

You should see testdb in the list.

🔹 Step 3: Delete the MySQL Pod

kubectl delete pod $(kubectl get pods -l app=mysql -o jsonpath="{.items[0].metadata.name}")

Wait for the Pod to restart.

🔹 Step 4: Check if Data is Still There
Reconnect and run:

SHOW DATABASES;

If testdb is still there, LocalPath Storage is working!


How to Remove LocalPath Storage?

To delete all storage:

kubectl delete -f mysql-deployment.yaml
kubectl delete -f mysql-pvc.yaml

To remove Local Path Provisioner:

kubectl delete -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml

Storage Network Volume in Kubernetes

What is it?

A Storage Network Volume in Kubernetes refers to storage that is accessible over a network, rather than being tied to a single node (server). It allows pods (containers) to read and write data even if they move between nodes.

Example:

Imagine you have an application running in Kubernetes that needs a shared database (like MySQL or PostgreSQL). If this database is running inside a pod and that pod crashes or moves to another node, you will lose data if it was stored only on the original node.

Solution:

Use a network-attached storage (NAS) like:

  • AWS EBS (Elastic Block Store)

  • Google Cloud Persistent Disk

  • NFS (Network File System)

  • CephFS (Distributed File System)

How it Works in Kubernetes?

You create a Persistent Volume (PV) and a Persistent Volume Claim (PVC) that requests storage from the network.

Example YAML:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-network-volume
spec:
  accessModes:
    - ReadWriteOnce  # Only one pod can write, but many can read
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard  # This uses cloud storage (AWS/GCP)

Key Benefits:

✔ Data survives even if the pod dies
✔ Accessible from multiple nodes
✔ Works with cloud providers and on-prem solutions

Kubernetes RBAC (Role-Based Access Control)

What is it?

RBAC controls who can do what in your Kubernetes cluster.

Example Scenario

Imagine your team has:

  • Developers (Can deploy apps)

  • Ops Team (Can restart servers)

  • Security Team (Read-only access)

RBAC Key Components

  1. Roles: Defines permissions (within a namespace)

  2. ClusterRoles: Defines permissions for the entire cluster

  3. RoleBinding: Grants a Role to a user or group

  4. ClusterRoleBinding: Grants a ClusterRole to a user

Example 1: Create a Role for Read-Only Access

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: read-only-role
rules:
- apiGroups: [""]
  resources: ["pods", "services"]
  verbs: ["get", "list"]
  • This allows users to only view pods and services in the default namespace.

Example 2: Bind Role to a User

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-only-binding
  namespace: default
subjects:
- kind: User
  name: john.doe  # Replace with actual username
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: read-only-role
  apiGroup: rbac.authorization.k8s.io
  • Now, john.doe can only read pods and services.

Kubernetes Service Account

What is a Service Account?

  • A Service Account is an identity used by pods to interact with the Kubernetes API.

  • Similar to how users log in with user accounts, pods use service accounts to perform actions inside the cluster.

  • By default, every pod uses the default service account unless we specify a custom one.

Why Use Service Accounts?

Control what a pod can access (RBAC permissions)
Prevent unauthorized actions (e.g., a pod deleting resources)
Better security (limit API access per application)


Example 1: Default Service Account

Every namespace has a default service account.

kubectl get serviceaccounts -n default

Output:

NAME      SECRETS   AGE
default   1         10d
  • This means any pod created in the default namespace automatically gets this service account.

Example 2: Create a Custom Service Account

Instead of using the default one, let's create a custom service account.

Step 1: Define a Service Account

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
  namespace: default

Apply it:

kubectl apply -f my-service-account.yaml

Step 2: Attach the Service Account to a Pod

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  serviceAccountName: my-service-account  # Attach custom service account
  containers:
  - name: my-container
    image: nginx

Now, this pod uses my-service-account instead of the default one.


Example 3: Grant Permissions to the Service Account

By default, a service account has no permissions. You must bind a Role or ClusterRole.

Step 1: Create a Role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
  • This role allows reading pod information.

Step 2: Bind the Role to the Service Account

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: default
subjects:
- kind: ServiceAccount
  name: my-service-account
  namespace: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Now, my-service-account can list pods but not delete them.

Kubernetes Security Context

What is a Security Context?

  • Security Context defines security settings for pods and containers.

  • It controls privileges, user permissions, and network security.

Why Use Security Context?

Prevent containers from running as root
Limit file access
Control Linux capabilities (e.g., disable dangerous syscalls)


Example 1: Run a Pod as a Non-Root User

By default, containers run as root, which is risky.

apiVersion: v1
kind: Pod
metadata:
  name: non-root-pod
spec:
  securityContext:
    runAsUser: 1000   # Run as user ID 1000 instead of root
    runAsGroup: 3000  # Run with group ID 3000
    fsGroup: 2000     # File system permissions
  containers:
  - name: my-container
    image: nginx
  • This ensures the pod does not run as root.

Example 2: Read-Only Root Filesystem

Prevent a container from modifying system files.

apiVersion: v1
kind: Pod
metadata:
  name: read-only-pod
spec:
  containers:
  - name: my-container
    image: nginx
    securityContext:
      readOnlyRootFilesystem: true  # Prevents writing to the root filesystem
  • This ensures the pod cannot modify its own files.

Example 3: Drop Linux Capabilities (Extra Privileges)

By default, containers inherit some Linux capabilities. Let’s drop them.

apiVersion: v1
kind: Pod
metadata:
  name: restricted-pod
spec:
  containers:
  - name: my-container
    image: nginx
    securityContext:
      capabilities:
        drop:
          - ALL  # Drop all Linux capabilities
  • This removes all extra privileges.

Example 4: Privileged Mode (Avoid This!)

Some containers need privileged mode to access host resources.

apiVersion: v1
kind: Pod
metadata:
  name: privileged-pod
spec:
  containers:
  - name: my-container
    image: nginx
    securityContext:
      privileged: true  # Full root access (Not Recommended)
  • ⚠️ WARNING: This gives full access to the node, which is a security risk.

Helm (Kubernetes Package Manager):

What is Helm?

Helm is like apt/yum (Linux) or npm (JavaScript) but for Kubernetes.
It simplifies the installation, management, and upgrading of Kubernetes applications. Instead of writing long YAML files, Helm uses charts (predefined templates) to deploy applications.

Why Use Helm?

Saves Time – No need to write huge Kubernetes YAML files.
Easy to Upgrade – Run one command to upgrade applications.
Version Control – Roll back to a previous version if needed.
Reusable – Share and reuse Helm charts.

The picture explains the concept well :

Example: Deploying Nginx with Helm

1️⃣ Install Helm

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

2️⃣ Add Helm Repo & Install Nginx

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install my-nginx bitnami/nginx

This deploys an Nginx web server on Kubernetes in seconds.

3️⃣ Check Deployment

kubectl get pods
kubectl get svc

4️⃣ Uninstall Nginx

helm uninstall my-nginx

🔹 Helm Chart Structure

A Helm chart is a folder with these files:

mychart/
  ├── Chart.yaml      # Chart metadata (name, version, description)
  ├── values.yaml     # Default configuration values
  ├── templates/      # Kubernetes YAML templates
  │   ├── deployment.yaml
  │   ├── service.yaml

To customize values:

helm install my-nginx bitnami/nginx --set service.type=LoadBalancer

This changes the service type from ClusterIP (default) to LoadBalancer.

Key Helm Concepts :

ConceptMeaningExample
ChartA Helm package containing Kubernetes YAML templatesbitnami/nginx
ReleaseA deployed instance of a Helm chart in a clustermy-nginx
RepositoryA collection of Helm chartshttps://charts.bitnami.com/bitnami
Values.yamlA file that stores configurable values for a Helm chartservice.type=LoadBalancer
Templates/A directory where Helm stores Kubernetes YAML templatesdeployment.yaml, service.yaml

Common Helm Commands :

CommandDescription
helm repo add <repo-name> <repo-url>Add a new Helm chart repository
helm repo updateUpdate all Helm chart repositories
helm search repo <chart-name>Search for a chart in repositories
helm install <release-name> <chart-name>Install a Helm chart
helm listShow all installed Helm releases
helm upgrade <release-name> <chart-name>Upgrade a Helm release
helm rollback <release-name> <revision>Roll back to a previous version
helm uninstall <release-name>Uninstall a Helm release
helm show values <chart-name>Display default values of a chart

WHY INGRESS CAME ?

Kubernetes Ingress is like a traffic cop for your Kubernetes cluster. It helps direct incoming traffic (like web requests) to the right services inside your cluster. Before Kubernetes, people used tools like Nginx, F5, or HAProxy to manage traffic on local VMs. These tools provided advanced features like ratio-based load balancing, sticky sessions, path-based routing, TLS termination, domain-based routing, white listing, back listing and more. But when Kubernetes first came out, its built-in load balancer was very basic and didn’t offer these advanced features. This disappointed people moving from traditional VMs to Kubernetes.

Additionally, Kubernetes initially had high costs for static public IPs used by load balancers. To solve these problems, the Kubernetes team introduced Ingress.

NOTE: Short explanations of the above mentioned features :

  1. Ratio-Based Load Balancing: Distributes traffic to backend servers based on a predefined ratio (e.g., 70% to Server A, 30% to Server B).

  2. Sticky Sessions: Ensures a user’s requests always go to the same backend server during their session.

  3. Path-Based Routing: Routes traffic to different services based on the URL path (e.g., /api goes to Service A, /app goes to Service B).

  4. TLS Termination: Decrypts HTTPS traffic at the gateway and sends it as plain HTTP to backend services.

  5. Domain-Based Routing: Routes traffic to different services based on the domain name (e.g., foo.com to Service A, bar.com to Service B).

  6. Whitelisting: Allows only specific IPs or users to access a service.

  7. Blacklisting: Blocks specific IPs or users from accessing a service.

Ingress acts as a smart gateway, routing traffic based on rules you define.

How Does Ingress Work?

  1. Ingress Resource: You define rules in a YAML file .

  2. Ingress Controller: The controller reads these rules and configures itself (e.g., Nginx) to route traffic accordingly.

Simplest Example : Default Backend

This is the simplest Ingress setup. All traffic is routed to a single service.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: test
      port:
        number: 80
  • What it does: Any traffic coming to your cluster will be sent to the test service on port 80.

Let’s see an example of Host-Based Routing:

This routes traffic based on the domain name (host).

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-with-auth
spec:
  rules:
    - host: foo.bar.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: http-svc
                port:
                  number: 80
    - host: example.bar.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: meow-svc
                port:
                  number: 80
  • What it does:

    • If someone visits foo.bar.com, they’ll be routed to the http-svc service.

    • If someone visits example.bar.com, they’ll be routed to the meow-svc service.

Let’s see a simple Ingress tutorial:

1. Enable Ingress in Minikube

Minikube doesn’t enable Ingress by default, so first, start Minikube and enable Ingress:

minikube start
minikube addons enable ingress

Verify that the Ingress controller is running:

kubectl get pods -n kube-system | grep ingress

You should see pods like ingress-nginx-controller running.


2. Deploy a Sample App

Let's create a simple Nginx deployment and expose it as a service.

# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80

Apply this deployment:

kubectl apply -f nginx-deployment.yaml

Now, expose it as a service:

kubectl expose deployment nginx-deployment --port=80 --target-port=80 --type=ClusterIP

Check the service:

kubectl get svc

You should see a ClusterIP service created for Nginx.


3. Create an Ingress Resource

Now, let’s define an Ingress resource to expose our Nginx service.

# nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: nginx.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-deployment
            port:
              number: 80

Apply the Ingress resource:

kubectl apply -f nginx-ingress.yaml

Check if the Ingress is created:

kubectl get ingress

4. Test Ingress

Since Minikube runs in a VM, you need to update your /etc/hosts file to resolve nginx.local to Minikube’s IP.

Find Minikube’s IP:

minikube ip

If Minikube IP is 192.168.49.2, update /etc/hosts :

192.168.49.2 nginx.local

Now, test in your browser or with curl:

curl http://nginx.local

You should see the default Nginx welcome page.