Kubernetes: The Start!

Kubernetes: The Start!

Β·

13 min read

I hope you found my last blog about Kubernetes basics and architecture helpful and worth your time. If you haven’t read it yet, please check it out before diving into this one, as the previous blog covers all the basics of Kubernetes: https://sahilnaik.hashnode.dev/kubernetes-the-end.

Learning through examples is a great way to understand complex concepts, and we'll be using examples in this blog too. So, why "Kubernetes: The Start"? Because we are going to cover Kubernetes, networking, and services concepts in this blog, marking the beginning of your Kubernetes learning journey.

We will explore these concepts using a small microservices project in Go. This project includes three microservices (Auth, Payment, Streaming) similar to those used by Netflix, which will help us understand the concepts more easily. Let's get started!


Project Overview:

Microservices Breakdown:

Our application consists of three independently deployable services, each responsible for a single, well-defined task:

  • Authentication Service: Handles user login and authentication.

  • Payment Service: Processes transactions and manages payment flows.

  • Streaming Service: Delivers video streaming content to users.


Kubernetes Concepts:

  1. Pods:

A Pod is the smallest deployable unit in Kubernetes. It encapsulates one or more containers, shared storage, network resources, and configurations. In our case, each microservice (Auth, Payment, Streaming) will run in its own Pod.

Each Pod:

  • Runs a single Go service (auth, payment, or streaming).

  • Uses a Docker container.

  • Has its own IP address.

  • Can be deployed and managed independently.

Setting Up the Microservices Project in Kubernetes

Here’s a step-by-step guide to setting up your Go microservices in Kubernetes:

Note: You can find all the source code for the microservices in Golang, along with the Dockerfile, in my GitHub repository listed in the resources section.

Step 1: Build and Push Docker Images

Before creating Pods, we need to build and push the Docker images.

  1. Navigate to each service directory and build the image:

     cd auth-service
     docker build -t your-dockerhub-username/auth-service .
    
     cd ../payment-service
     docker build -t your-dockerhub-username/payment-service .
    
     cd ../streaming-service
     docker build -t your-dockerhub-username/streaming-service .
    
  2. Tag Images:

     docker tag auth-service:latest your-dockerhub-username/auth-service
     docker tag payment-service:latest your-dockerhub-username/payment-service
     docker tag streaming-service:latest your-dockerhub-username/streaming-service
    
  3. Push images to Docker Hub or any container registry:

     docker push your-dockerhub-username/auth-service:latest
     docker push your-dockerhub-username/payment-service:latest
     docker push your-dockerhub-username/streaming-service:latest
    

Step 2: Write the Pod YAML Files

Each service will have its own Pod definition.

Pod YAML for Auth Service (auth-pod.yaml)

apiVersion: v1  # Uses the core API version 'v1' since Pods are a fundamental resource in Kubernetes.
kind: Pod  # Defines this as a Pod resource.
metadata:
  name: auth-service  # The name of the Pod.
  labels:
    app: auth-service  # Labels help in identifying and selecting this Pod (used by Services, ReplicaSets, etc.).
spec:
  containers:  # Specifies the list of containers inside the Pod.
  - name: auth-service  # The name of the container inside the Pod.
    image: your-dockerhub-username/auth-service:latest  # The Docker image used to run the container.
    ports:
    - containerPort: 8081  # Exposes port 8081 inside the Pod for incoming traffic.

Pod YAML for Payment Service (payment-pod.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: payment-service
  labels:
    app: payment-service
spec:
  containers:
  - name: payment-service
    image: your-dockerhub-username/payment-service:latest
    ports:
    - containerPort: 8082

Pod YAML for Streaming Service (streaming-pod.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: streaming-service
  labels:
    app: streaming-service
spec:
  containers:
  - name: streaming-service
    image: your-dockerhub-username/streaming-service:latest
    ports:
    - containerPort: 8083

Step 3: Deploy the Pods in Kubernetes

  • Ensure Minikube or Kubernetes cluster is running:

      minikube start  # If using Minikube
    
  • Apply the YAML files:

      kubectl apply -f auth-pod.yaml
      kubectl apply -f payment-pod.yaml
      kubectl apply -f streaming-pod.yaml
    
  • Check if Pods are running:

      kubectl get pods
    
  • Get logs for a specific Pod:

      kubectl logs auth-service
    
  • Access a Pod directly:

      kubectl port-forward auth-service 8081:8081
    

    Now, you can access the Auth service at http://localhost:8081.

    You might be thinking, if there are containers and we can run them, why do we use pods?

    1. Pods Provide an Abstraction Layer Over Containers

      Kubernetes doesn’t manage standalone containers. Instead, it manages Pods, which encapsulate one or more containers. This abstraction makes it easier to manage and schedule workloads in a Kubernetes cluster.

      Example:
      If Kubernetes managed containers directly, scaling and networking each container individually would be complex. Pods simplify this by treating a set of containers as a single unit.

    2. Pods Can Contain Multiple Containers That Share Resources

      A Pod can run multiple tightly coupled containers that need to share resources (like storage and networking).

      Example:
      Imagine a logging sidecar container that collects logs from your main application container. Both containers can be in the same Pod, sharing the same network and storage. If containers were standalone, this would require extra configuration.

    3. Pods Enable Scaling & Load Balancing

      A single container can’t scale well. Instead of scaling a single container, Kubernetes scales Pods using ReplicaSets or Deployments. This ensures high availability and distributes traffic efficiently.

      Example:
      If you get high traffic on the auth-service, Kubernetes can create multiple instances of the auth-service Pod and load balance traffic across them.

      | Feature | Standalone Container | Kubernetes Pod | | --- | --- | --- | | Networking | Needs manual IP management | Each Pod has an IP, DNS handles discovery | | Scaling | Manual scaling | ReplicaSets scale Pods automatically | | Restart on Failure | Needs manual restart | Kubernetes restarts failed Pods | | Multiple Containers Together | Hard to manage | Containers in a Pod share storage/network | | Load Balancing | Needs external setup | Kubernetes balances traffic across Pods |


  1. ReplicaSet:

A ReplicaSet ensures that a specified number of identical Pods are always running.
βœ… If a Pod fails, it automatically recreates it.
βœ… If a node crashes, it reschedules Pods on another node.
βœ… If traffic increases, you can scale up by adding more replicas.

πŸ“Œ Think of a ReplicaSet as an auto-restart and scaling mechanism for Pods.

Why Use a ReplicaSet Instead of Just Pods?

FeaturePodReplicaSet
Ensures a fixed number of running instances❌ Noβœ… Yes
Automatically restarts crashed Pods❌ Noβœ… Yes
Distributes Pods across nodes❌ Noβœ… Yes
Scales up/down dynamically❌ Noβœ… Yes

Example:

  • You have an auth-service that needs 3 running instances for high availability.

  • Instead of manually creating 3 Pods, you define a ReplicaSet with replicas: 3.

  • If 1 Pod crashes, Kubernetes automatically recreates it.

πŸ“Œ Let's create a auth-replicaset.yaml file.

apiVersion: apps/v1    # ReplicaSets belong to the 'apps' API group, hence 'apps/v1'
kind: ReplicaSet       # Defines this as a ReplicaSet resource
metadata:
  name: auth-replicaset  # Name of the ReplicaSet
  labels:
    app: auth-service    # Labels for identifying the ReplicaSet

spec:
  replicas: 3            # Number of pod replicas to maintain
  selector:
    matchLabels:
      app: auth-service  # Selects Pods with this label to manage

  template:              # Template for the Pods that will be created
    metadata:
      labels:
        app: auth-service  # Labels to assign to the created Pods

    spec:
      containers:
      - name: auth-service  # Name of the container
        image: nsahil992/auth-service:latest  # Docker image to use
        ports:
          - containerPort: 8081  # Expose port 8081 inside the pod

Explanation of ReplicaSet YAML:

FieldDescription
kind: ReplicaSetDefines a ReplicaSet resource.
metadata.nameName of the ReplicaSet (auth-replicaset).
spec.replicasNumber of desired replicas (3 Pods).
spec.selector.matchLabelsEnsures the ReplicaSet manages only Pods with app: auth-service.
spec.templateDefines the Pod that should be replicated.
spec.template.metadata.labelsThese labels must match the selector.
spec.template.spec.containersContainer details (image, ports, etc.).

How to Deploy the ReplicaSet?

1️⃣ Apply the YAML file:

kubectl apply -f auth-replicaset.yaml

2️⃣ Verify the ReplicaSet:

kubectl get replicaset

βœ… Output:

NAME               DESIRED   CURRENT   READY   AGE
auth-replicaset   3         3         3       10s

3️⃣ Check the running Pods:

kubectl get pods

βœ… Output:

NAME                        READY   STATUS    RESTARTS   AGE
auth-replicaset-xyz1        1/1     Running   0          5s
auth-replicaset-xyz2        1/1     Running   0          5s
auth-replicaset-xyz3        1/1     Running   0          5s

Notice that the Pods have unique names, but they are managed by the auth-replicaset.

How to Scale the ReplicaSet?

You can manually increase or decrease the number of Pods.

πŸ”Ή Scale up to 5 Pods:

kubectl scale replicaset auth-replicaset --replicas=5

πŸ”Ή Check the updated ReplicaSet:

kubectl get replicaset

βœ… Output:

NAME               DESIRED   CURRENT   READY   AGE
auth-replicaset   5         5         5       1m

πŸ”Ή Check new Pods:

kubectl get pods

Now, you'll see 5 running Pods.

What Happens If a Pod Fails?

If a Pod crashes or is deleted, the ReplicaSet automatically creates a new one.

πŸ”Ή Delete a Pod manually:

kubectl delete pod auth-replicaset-xyz1

πŸ”Ή Check running Pods again:

kubectl get pods

βœ… A new Pod is created automatically!
The total number of Pods remains 3, as defined in replicas: 3.


  1. Deployments:

    A Deployment is a higher-level controller that:
    πŸ”Ή Manages ReplicaSets automatically.
    πŸ”Ή Allows updating services without downtime.
    πŸ”Ή Provides rollback in case of failure.

    πŸ’‘ Think of a Deployment as a manager for ReplicaSets! It makes sure your Pods are updated efficiently and safely.

    Why Use a Deployment Instead of a ReplicaSet?

    | Feature | ReplicaSet | Deployment | | --- | --- | --- | | Ensures a fixed number of running Pods | βœ… Yes | βœ… Yes | | Automatically restarts crashed Pods | βœ… Yes | βœ… Yes | | Supports versioned updates (rolling updates) | ❌ No | βœ… Yes | | Provides rollback on failure | ❌ No | βœ… Yes | | Easy scaling & management | ⚠️ Manual | βœ… Yes |

    βœ… Deployments manage ReplicaSets and provide update strategies, making them essential for production!

    πŸ“Œ Create auth-deployment.yaml

     apiVersion: apps/v1
     kind: Deployment
     metadata:
       name: auth-deployment
       labels:
         app: auth-service
    
     spec:
       replicas: 3  # Number of Pod replicas
       selector:
         matchLabels:
           app: auth-service  # Must match Pod labels
    
       template:
         metadata:
           labels:
             app: auth-service
    
         spec:
           containers:
           - name: auth-service
             image: your-dockerhub-username/auth-service:latest
             ports:
             - containerPort: 8081
    

    How to Deploy the auth-service Deployment?

    1️⃣ Apply the Deployment:

     kubectl apply -f auth-deployment.yaml
    

    2️⃣ Check the Deployment & Pods:

     kubectl get deployments
     kubectl get pods
    

    βœ… Output:

     NAME              READY   UP-TO-DATE   AVAILABLE   AGE
     auth-deployment   3/3     3            3          10s
    
     NAME                                  READY   STATUS    RESTARTS   AGE
     auth-deployment-xyz1                   1/1     Running   0          5s
     auth-deployment-xyz2                   1/1     Running   0          5s
     auth-deployment-xyz3                   1/1     Running   0          5s
    

    πŸ”Ή The Deployment automatically creates a ReplicaSet and Pods for us.

    Rolling Updates (Upgrading the Service Without Downtime)

    Imagine you want to update the auth-service to a new version (e.g., v2.0).

    1️⃣ Edit the Deployment YAML to update the image:

     spec:
       template:
         spec:
           containers:
           - name: auth-service
             image: your-dockerhub-username/auth-service:v2.0
    

    2️⃣ Apply the updated Deployment:

     kubectl apply -f auth-deployment.yaml
    

    3️⃣ Check the rollout status:

     kubectl rollout status deployment auth-deployment
    

    βœ… Pods are updated one by one (zero downtime).


    Rollback to a Previous Version (In Case of Failure)

    If the new version has issues, rollback easily:

    1️⃣ Check Deployment history:

     kubectl rollout history deployment auth-deployment
    

    2️⃣ Rollback to the previous version:

     kubectl rollout undo deployment auth-deployment
    

    βœ… It automatically restores the previous version of Pods!


    Scaling a Deployment

    1️⃣ Increase the number of Pods dynamically:

     kubectl scale deployment auth-deployment --replicas=5
    

    2️⃣ Verify the new replicas:

     kubectl get pods
    

    βœ… Now you have 5 running instances of auth-service.


  1. Services:

Pods have dynamic IPs, meaning they get a new IP whenever they restart. This makes direct Pod-to-Pod communication unreliable. Services solve this problem by providing:
πŸ”Ή A fixed IP and DNS name to access the Pods.
πŸ”Ή Load balancing between multiple Pod replicas.
πŸ”Ή The ability to expose applications externally.

Types of Kubernetes Services

  1. ClusterIP (default):

    • Internal communication: Exposes the service inside the Kubernetes cluster.

    • Pods can reach the service using its DNS name (e.g., auth-service).

    • External clients cannot access this service directly.

  2. NodePort:

    • External access: Exposes the service on a static port across all nodes in the cluster.

    • You can access the service using <NodeIP>:<NodePort>.

    • Typically used for development and testing.

  3. LoadBalancer:

    • External access with load balancing: Exposes the service using an external load balancer.

    • Automatically provisions an external IP (commonly used in cloud environments like AWS or GCP).

    • Routes traffic to your service, ensuring load balancing across Pods.

  4. ExternalName:

    • Maps the service to an external DNS name, such as a service hosted outside the Kubernetes cluster.

    • Used for integrating with external services.

How Does a Service Work?

  1. Selects Pods: A Service selects the Pods it targets using labels and selectors.

  2. Provides a stable endpoint: The Service gives a stable IP address and DNS name to interact with, even though the Pods themselves may change over time.

  3. Load balancing: Services automatically distribute traffic to available Pods.

apiVersion: v1
kind: Service
metadata:
  name: auth-service      # The name of the Service
spec:
  selector:
    app: auth-service     # Pods with this label are targeted by the service
  ports:
    - protocol: TCP
      port: 8081           # Port on which the service is exposed
      targetPort: 8081     # Port inside the Pod that the service will forward traffic to
  type: ClusterIP         # Type of service (default is ClusterIP)
  • spec.ports:

    • port: 8081: The port that will be exposed by the service.

    • targetPort: 8081: The port that the service will forward traffic to in the Pod.

  • type: ClusterIP:

    • This makes the service accessible only inside the cluster.

    • Kubernetes assigns a virtual IP (ClusterIP) to the service, and traffic directed to this IP will be forwarded to the selected Pods.

How the Service Works with Pods

Example:

Assume you have a Deployment for your auth-service with three Pods. You can expose this deployment using a Service.

  1. Pods are running (let's say they are on Pods auth-service-xyz123, auth-service-abc456, auth-service-def789).

  2. The Service is created (using the above YAML). The service now has an IP, e.g., 10.0.0.1, which will automatically route traffic to any available Pods with the label app: auth-service.

  3. When a user sends a request to the service's IP, the Service will forward it to one of the Pods in the set.

Types of Services in Action

1. ClusterIP (Internal access only):

apiVersion: v1
kind: Service
metadata:
  name: auth-service
spec:
  selector:
    app: auth-service
  ports:
    - protocol: TCP
      port: 8081
      targetPort: 8081
  type: ClusterIP
  • Pods inside the cluster can access auth-service at auth-service:8081.

  • External traffic cannot access this service.

2. NodePort (External access via NodeIP and port):

apiVersion: v1
kind: Service
metadata:
  name: auth-service
spec:
  selector:
    app: auth-service
  ports:
    - protocol: TCP
      port: 8081
      targetPort: 8081
      nodePort: 30001    # Exposes the service on port 30001 across all nodes
  type: NodePort
  • This service will be available externally on NodeIP:30001.

  • Traffic coming to any node's IP at port 30001 will be forwarded to the Pods.

3. LoadBalancer (For cloud environments):

yamlCopyEditapiVersion: v1
kind: Service
metadata:
  name: auth-service
spec:
  selector:
    app: auth-service
  ports:
    - protocol: TCP
      port: 8081
      targetPort: 8081
  type: LoadBalancer
  • In cloud environments (like AWS), this will provision an external load balancer, and traffic from outside the cluster will be directed to your service.

Resources and file system:

microservices-project/
│── auth-service/
β”‚   β”œβ”€β”€ main.go
β”‚   β”œβ”€β”€ Dockerfile
β”‚   β”œβ”€β”€ go.mod
β”‚   β”œβ”€β”€ go.sum
β”‚   β”œβ”€β”€ k8s/
β”‚   β”‚   β”œβ”€β”€ auth-pod.yaml
β”‚   β”‚   β”œβ”€β”€ auth-replicaset.yaml
β”‚   β”‚   β”œβ”€β”€ auth-deployment.yaml
β”‚   β”‚   β”œβ”€β”€ auth-service.yaml
β”‚   
β”‚
│── payment-service/
β”‚   β”œβ”€β”€ main.go
β”‚   β”œβ”€β”€ Dockerfile
β”‚   β”œβ”€β”€ go.mod
β”‚   β”œβ”€β”€ go.sum
β”‚   β”œβ”€β”€ k8s/
β”‚   β”‚   β”œβ”€β”€ payment-pod.yaml
β”‚   β”‚   β”œβ”€β”€ payment-replicaset.yaml
β”‚   β”‚   β”œβ”€β”€ payment-deployment.yaml
β”‚   β”‚   β”œβ”€β”€ payment-service.yaml
β”‚  
β”‚
│── streaming-service/
β”‚   β”œβ”€β”€ main.go
β”‚   β”œβ”€β”€ Dockerfile
β”‚   β”œβ”€β”€ go.mod
β”‚   β”œβ”€β”€ go.sum
β”‚   β”œβ”€β”€ k8s/
β”‚   β”‚   β”œβ”€β”€ streaming-pod.yaml
β”‚   β”‚   β”œβ”€β”€ streaming-replicaset.yaml
β”‚   β”‚   β”œβ”€β”€ streaming-deployment.yaml
β”‚   β”‚   β”œβ”€β”€ streaming-service.yaml
β”‚   
β”œβ”€β”€ README.md

GitHub (Source Code): https://github.com/nsahil992/K8s-Microservice-Project


Learning Resources:

Kodekloud: https://learn.kodekloud.com/user/courses/kubernetes-for-the-absolute-beginners-hands-on-tutorial


Thank you for taking the time to read this. If you enjoy my work, consider subscribing to my newsletter to get updates as soon as I post a new blog. If you like the repository, consider giving it a ⭐️ and feel free to connect with me on my social media:

LinkedIn: https://www.linkedin.com/in/nsahil992

GitHub: https://github.com/nsahil992

Twitter/X: https://twitter.com/nsahil992


Β