Lesson  in  Kubelings — Learn Kubernetes the Rustlings Way

Service types: open a door to the outside

The demo works inside the cluster, but the client wants to hit it from their laptop. Promote the ClusterIP Service to NodePort on 30080 and understand the ladder: ClusterIP → NodePort → LoadBalancer — what each adds, and what each costs.

The situation

Demo day. The demo Service works beautifully — from inside the cluster. ClusterIP is exactly that: a virtual IP that exists only in cluster routing. The client on the guest Wi-Fi types it into a browser and gets nothing, because outside the cluster that IP is fiction.

The Service type ladder, each rung adding exposure:

TypeAddsReachable from
ClusterIPstable VIP + DNSpods only (default, correct for most things)
NodePortsame port opened on every nodeanyone who can reach any node IP
LoadBalancercloud LB pointing at the NodePortsthe internet (cloud-managed)

LoadBalancer needs a cloud controller — on bare kind it stays <pending> forever. Today's tool is NodePort: kube-proxy programs every node to forward a high port (default range 30000–32767) into the Service.

    ┌───────────────┐     
    │client outside │     
    │               │     
    └───────────────┘     
           │              
   node IP and port       
           │              
           ▼              
  ┌─────────────────┐     
  │NodePort on node │     
  │                 │     
  └─────────────────┘     
           │              
  then normal routing     
           │              
           ▼              
 ┌───────────────────────┐
 │ClusterIP, inside only │
 │                       │
 └───────────────────────┘

Your task

  1. Make Service demo type NodePort with nodePort: 30080 (pinned, so the check — and your client — knows where to knock).
  2. Confirm it answers on a node's InternalIP:30080.
kubectl -n kubelings get svc demo
kubectl get nodes -o wide    # InternalIP column
Hint
kubectl -n kubelings patch svc demo --type=merge -p '
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080
'
NIP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
wget -qO- http://$NIP:30080/
Solution

What NodePort actually does

kube-proxy adds a rule on every node — including nodes running zero demo pods: "packets to me:30080 → demo endpoints." Hit any node, reach the service; the mesh routes across nodes internally. That's why it works and why it's wasteful: every node donates a port from a small shared range (30000–32767, ~2700 doors for the whole cluster).

The ladder in practice

  • ClusterIP — default. If nothing outside the cluster needs it, stop here. Every extra rung is attack surface (ask JW Player — Module 6).
  • NodePort — demos, on-prem edges, and the substrate LoadBalancers build on. Couples clients to node IPs, which change.
  • LoadBalancer — production external traffic, one cloud LB per Service (cost!). On kind: pending forever, no cloud controller.
  • Beyond the ladder: Ingress/Gateway — one LB, many routes, L7. Different lesson.

Fix

The patch from the hint. Check the wiring end to end:

kubectl -n kubelings get svc demo
# PORT(S): 80:30080/TCP  ← service port : node port

Prevention / habits

  • Pin nodePort only when something external hardcodes it (like this check); otherwise let Kubernetes pick and avoid range collisions.
  • Audit exposure regularly: kubectl get svc -A | grep -v ClusterIP — every row is a door to the outside. Every door should have a reason you can say out loud.