Kubernetes Services in Action: ClusterIP, NodePort, LoadBalancer + Manual Scheduling

Dechen TsheringDechen Tshering
3 min read

Hi Devs and DevOps friends! 👋

As part of my DevOps learning in public, I’ve been diving deep into Kubernetes and exploring how Services work—particularly how to expose applications inside and outside the cluster using different service types.

In this blog, I’ll walk you through my experiments using ClusterIP, NodePort, and LoadBalancer, along with a quick intro to manual pod scheduling on specific nodes.

Let’s go!

Step 1: Create a ReplicaSet

# myapp.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: webapp
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: mycontainer
        image: nginx

Apply it:

kubectl apply -f myapp.yml

Demo 1: ClusterIP

# cip.yml
apiVersion: v1
kind: Service
metadata:
  name: mysvc
spec:
  type: ClusterIP
  ports:
  - targetPort: 80     # container port
    port: 5000         # service port
  selector:
    app: web

Or expose it using the CLI:

kubectl expose rs webapp --target-port=80 --port=5000 --name=mysvc

Access It:

Start a debug pod on that node:

kubectl debug node/<NODE_NAME> -it --image=nginx

Inside the pod:

apt-get update -y && apt-get install curl -y
curl <SERVICE_IP>:5000

Demo 2: NodePort

NodePort allows you to access your service externally on a static port on any worker node.

# nodeport.yml
apiVersion: v1
kind: Service
metadata:
  name: web-node-port
spec:
  type: NodePort
  ports:
  - targetPort: 80
    port: 80
    nodePort: 30002
  selector:
    app: web

Or use:

kubectl expose rs webapp --target-port=80 --port=80 --type=NodePort

Access It:

Curl from a debug pod:

curl <NODE_IP>:30002

Demo 3: LoadBalancer

LoadBalancer is commonly used in cloud environments to expose services publicly using an external IP.

# lb.yml
apiVersion: v1
kind: Service
metadata:
  name: mysvc
spec:
  type: LoadBalancer
  ports:
  - targetPort: 80
    port: 80
  selector:
    app: web

Or via CLI:

kubectl expose rs webapp --target-port=80 --port=80 --type=LoadBalancer

Access It:

kubectl get svc
# Use the external IP shown to access your app in the browser

Note: This works on cloud providers like GCP, AWS, or Azure. On Minikube or bare metal, you may need MetalLB or another load balancer.

Bonus: Manual Scheduling

I also tried manually scheduling a pod to a specific node. This can be helpful when testing specific node configurations or behavior.

# pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: abc
spec:
  containers:
  - name: abc
    image: nginx
  nodeName: <NODE_NAME>

Just replace <NODE_NAME> with a real node name from:

kubectl get nodes

Apply it:

kubectl apply -f pod.yml

Key Learnings

  • ClusterIP: Great for internal communication between services.

  • NodePort: Exposes apps on every node's IP at a static port.

  • LoadBalancer: Best for public access when running on cloud providers.

  • Manual scheduling gives control, but use it with caution in production.

If you're also learning Kubernetes, let’s connect and grow together! 🌱
Drop a comment if this was helpful or if you’ve got tips of your own 🙌

0
Subscribe to my newsletter

Read articles from Dechen Tshering directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Dechen Tshering
Dechen Tshering