Table of contents
- Project Overview:
- Kubernetes Concepts:
- Pods:
- ReplicaSet:
- How to Deploy the ReplicaSet?
- Deployments:
- How to Deploy the auth-service Deployment?
- Rollback to a Previous Version (In Case of Failure)
- Scaling a Deployment
- Services:
- Resources and file system:
- Learning Resources:
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:
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.
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 .
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
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?
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.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.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 theauth-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 |
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?
Feature | Pod | ReplicaSet |
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:
Field | Description |
kind: ReplicaSet | Defines a ReplicaSet resource. |
metadata.name | Name of the ReplicaSet (auth-replicaset ). |
spec.replicas | Number of desired replicas (3 Pods). |
spec.selector.matchLabels | Ensures the ReplicaSet manages only Pods with app: auth-service . |
spec.template | Defines the Pod that should be replicated. |
spec.template.metadata.labels | These labels must match the selector . |
spec.template.spec.containers | Container 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
.
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
.
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
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.
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.
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.
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?
Selects Pods: A Service selects the Pods it targets using labels and selectors.
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.
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.
Pods are running (let's say they are on Pods
auth-service-xyz123
,auth-service-abc456
,auth-service-def789
).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 labelapp: auth-service
.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
atauth-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