Skip to main content

Settings

Color Mode
Theme Skin
Background

Appearance preferences are saved in this browser only.

Environment
Current Environment Production

Built with JEKYLL_ENV=production. Changes require deployment.

Quick Links
Theme & Build
Jekyll v3.10.0
Last Build Sep 01, 14:30
Page Location
Page Info
Layout quest
Collection quests
Path _quests/1001/k8s-services-networking.md
URL /quests/1001/k8s-services-networking/
Date 2025-11-29

Kubernetes Services and Networking: Ingress and DNS

Master Kubernetes networking with Services, Ingress, and cluster DNS, choosing between ClusterIP, NodePort, and LoadBalancer to expose workloads.

Table of Contents

🔥 Lvl 1001Warrior 🏰 Main Quest 🔴 Hard 90-120 minutes

Kubernetes Services and Networking: Ingress and DNS

Configure Kubernetes networking with Services, Ingress, and DNS for scalable applications

Primary Tech
🛠️ kubernetes
Skill Focus
Devops
Series
Kubernetes Mastery
Author
IT-Journey Team
XP Range
⚡ 3750-4500

Your Environment

Showing every platform path

Warrior, your workloads now run resilient and self-healing - but they are islands. Pods are mortal: they are born, they die, and their IP addresses vanish with them. How then does one Pod find another? How does the outside world reach your service when the very addresses keep shifting? This quest teaches the roads, gates, and naming of the cluster: Services that give workloads a stable identity, DNS that lets them find each other by name, and Ingress that opens the gates to the world beyond.

Whether you are wiring a frontend to a backend, exposing an API to the internet, or debugging why a request never arrives, this adventure forges the networking intuition every cluster Warrior needs.

📖 The Legend Behind This Quest

In the old realms, a server had one address, written on a scroll and never changed. In the cluster, addresses are ephemeral - a Pod replaced during a rollout takes a new IP, and any client holding the old one is lost. Kubernetes solved this with an abstraction: the Service, a stable virtual address and name that always points at whichever Pods are currently healthy. Layered atop it, Ingress provides a single smart gate that routes external traffic by hostname and path. Together they turn a shifting sea of Pods into a dependable map.

This quest teaches the “why” behind every connection in your cluster. Master it, and the network stops being a mystery and becomes a tool.

🎯 Quest Objectives

By the time you complete this epic journey, you will have mastered:

Primary Objectives (Required for Quest Completion)

  • The Service Abstraction - Give a set of Pods a single stable virtual IP and DNS name
  • Service Types - Choose correctly between ClusterIP, NodePort, and LoadBalancer
  • Cluster DNS and Discovery - Resolve a Service by name from inside a Pod
  • Ingress Routing - Route external HTTP traffic by host and path through one entry point

Secondary Objectives (Bonus Achievements)

  • Endpoints - Inspect how a Service maps its selector to live Pod IPs
  • NetworkPolicies - Restrict which Pods may talk to which
  • Troubleshooting - Diagnose a Service returning no endpoints

Mastery Indicators

You’ll know you’ve truly mastered this quest when you can:

  • Explain why a Service is needed even though Pods already have IPs
  • Pick the right Service type for internal, dev, and production exposure
  • Resolve service.namespace.svc.cluster.local and explain each segment
  • Find why a Service has zero endpoints from kubectl describe

🗺️ Quest Prerequisites

📋 Knowledge Requirements

🛠️ System Requirements

  • Modern operating system (Windows 10+, macOS 10.14+, or Linux)
  • A running local cluster (kind, minikube, or k3d)
  • kubectl configured and on your PATH

🧠 Skill Level Indicators

This 🔴 Hard quest expects:

  • You can deploy and scale a workload
  • You are ready to reason about how traffic reaches a Pod
  • Ready for 90-120 minutes of hands-on practice

🌍 Choose Your Adventure Platform

Services and DNS work identically everywhere. Ingress requires a controller, which differs by platform - we’ll use the NGINX Ingress controller, available on every cluster type.

🍎 macOS Kingdom Path

Click to expand macOS instructions
# Deploy a backend workload to expose
kubectl create deployment web --image=nginx:1.27 --replicas=3
# Install the NGINX Ingress controller (kind variant)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller --timeout=120s

🪟 Windows Empire Path

Click to expand Windows instructions
kubectl create deployment web --image=nginx:1.27 --replicas=3
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=120s

🐧 Linux Territory Path

Click to expand Linux instructions
# On minikube, the addon is the simplest route:
minikube addons enable ingress
# On kind, apply the controller manifest:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl create deployment web --image=nginx:1.27 --replicas=3

☁️ Cloud Realms Path

Click to expand Cloud/Container instructions
# On managed clusters, a Service of type LoadBalancer provisions a real cloud LB:
kubectl expose deployment web --type=LoadBalancer --port=80
kubectl get service web --watch   # EXTERNAL-IP fills in when the cloud LB is ready

Cloud-Specific Notes:

  • LoadBalancer only provisions an external IP on clouds; locally it stays <pending>.
  • Managed clusters also offer cloud-native Ingress controllers (AWS ALB, GKE Ingress).

🧙‍♂️ Chapter 1: The Service - A Stable Address Over Shifting Pods

Pods come and go, and each gets a fresh IP. A Service is a stable virtual IP (the ClusterIP) plus a DNS name that always forwards to whichever Pods currently match its selector. This is the cornerstone of all Kubernetes networking.

⚔️ Skills You’ll Forge in This Chapter

  • How a Service selector maps to live Pod endpoints
  • The ClusterIP type for internal communication
  • Inspecting the Endpoints object behind a Service

🏗️ Define a Service

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: ClusterIP          # internal-only stable virtual IP (the default)
  selector:
    app: web               # routes to every Pod carrying label app=web
  ports:
    - port: 80             # the port the Service listens on
      targetPort: 80       # the container port it forwards to
      protocol: TCP
# Apply it and inspect what it found
kubectl apply -f web-service.yaml
kubectl get service web
kubectl get endpoints web      # the live Pod IPs the Service forwards to
kubectl describe service web   # selector, ports, and endpoints in one view

The Endpoints object is the magic: the Service controller watches Pods matching the selector and keeps this list of healthy Pod IPs current. If the list is empty, the Service has nothing to forward to - the single most common Service bug.

🔍 Knowledge Check: The Service

  • What links a Service to the Pods it serves?
  • What is the difference between port and targetPort?
  • What does an empty Endpoints list tell you?

⚡ Quick Wins and Checkpoints

  • Service Created: kubectl get service web shows a ClusterIP
  • Endpoints Populated: kubectl get endpoints web lists Pod IPs

🧙‍♂️ Chapter 2: Service Types and Cluster DNS - Reaching In and Finding by Name

A ClusterIP is invisible from outside the cluster. To open it up, you choose a Service type. And to let Pods find each other, every Service gets a predictable DNS name.

⚔️ Skills You’ll Forge in This Chapter

  • The three exposure types and when to use each
  • The cluster DNS naming scheme
  • Service discovery from inside a Pod

🏗️ The Three Service Types

Type What it does Use when
ClusterIP Internal-only virtual IP (default) Pod-to-Pod traffic inside the cluster
NodePort Opens a port (30000-32767) on every node Quick external access in dev / on-prem
LoadBalancer Provisions a cloud load balancer with a public IP Production external access on a cloud
# A NodePort Service: reach the app at <node-ip>:30080
apiVersion: v1
kind: Service
metadata:
  name: web-nodeport
spec:
  type: NodePort
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080      # fixed node port (omit to let Kubernetes pick one)

🏗️ Cluster DNS - Finding Services by Name

Kubernetes runs an internal DNS service (CoreDNS). Every Service is resolvable at:

<service-name>.<namespace>.svc.cluster.local

From a Pod in the same namespace, the short name web is enough. Prove it:

# Launch a throwaway Pod and resolve the Service by name.
# Use ';' (not '&&'): busybox nslookup exits non-zero after probing the standard
# search domains even when the short name resolves, which would skip the wget.
kubectl run netcheck --rm -it --image=busybox:1.36 --restart=Never -- \
  sh -c "nslookup web; wget -qO- http://web"

# Full FQDN works across namespaces:
kubectl run netcheck --rm -it --image=busybox:1.36 --restart=Never -- \
  nslookup web.default.svc.cluster.local

This is service discovery: your frontend connects to http://backend and never needs to know a Pod IP. CoreDNS resolves the name to the Service’s stable ClusterIP, and the Service load-balances across healthy Pods.

🔍 Knowledge Check: Types and DNS

  • When would you pick NodePort over LoadBalancer?
  • What does each segment of web.default.svc.cluster.local mean?
  • Why can a frontend hardcode http://backend safely?

🧙‍♂️ Chapter 3: Ingress and NetworkPolicy - The Smart Gate and the Walls

Exposing every service as its own LoadBalancer is wasteful and costly. Ingress is a single smart gate that routes external HTTP(S) traffic to many Services by hostname and path. NetworkPolicy then lets you wall off who may talk to whom.

⚔️ Skills You’ll Forge in This Chapter

  • Routing external traffic with Ingress rules
  • Host- and path-based routing
  • Restricting traffic with NetworkPolicy

🏗️ An Ingress Rule

An Ingress needs an Ingress controller running in the cluster (installed in the platform step). The Ingress resource then declares routing rules:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: app.local        # route requests for this hostname
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web     # forward to the 'web' Service
                port:
                  number: 80
# Apply the Ingress and verify it
kubectl apply -f web-ingress.yaml
kubectl get ingress web-ingress

# Test it. Send the Host header:
curl -H "Host: app.local" http://localhost/

kind users - map the host ports first. A default kind create cluster maps only the API server to your host, so nothing listens on localhost:80 and the curl above fails with connection refused. Create (or recreate) the cluster with extraPortMappings and the ingress-ready node label before installing the ingress-nginx controller, per kind’s ingress guide:

kind create cluster --config - <<'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
      - containerPort: 443
        hostPort: 443
EOF

One Ingress can route app.local/ to the web Service and app.local/api to an API Service - many backends behind one gate.

🏗️ NetworkPolicy - Default-Deny Walls

By default, every Pod can talk to every other Pod. A NetworkPolicy restricts this. This policy says: Pods labeled app=db accept traffic only from Pods labeled app=web:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-web
spec:
  podSelector:
    matchLabels:
      app: db
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: web
      ports:
        - protocol: TCP
          port: 5432

Note: NetworkPolicies only take effect if your cluster’s CNI plugin enforces them (Calico, Cilium). The kind default CNI does not - install Calico to practice enforcement.

🔍 Knowledge Check: Ingress and Policy

  • What does an Ingress give you that many LoadBalancers do not?
  • What must be running in the cluster for an Ingress resource to work?
  • What is the default Pod-to-Pod traffic posture before any NetworkPolicy?

🎮 Mastery Challenges

🟢 Novice Challenge: Expose with a ClusterIP

Objective: Put a stable internal address in front of the web Deployment.

Requirements:

  • Create a ClusterIP Service selecting app=web
  • Confirm its Endpoints list the Pod IPs
  • Reach it by name from a throwaway Pod

Validation: wget -qO- http://web from inside the cluster returns the nginx page.

🟡 Intermediate Challenge: Resolve and Route

Objective: Prove DNS discovery and add NodePort access.

Requirements:

  • nslookup web resolves to the ClusterIP from a Pod
  • Add a NodePort Service and reach it on a node port
  • Explain each segment of the FQDN

Validation: You can curl the app via both the cluster DNS name and the node port.

🔴 Advanced Challenge: Gate It With Ingress

Objective: Route external traffic through a single Ingress.

Requirements:

  • Install/verify an Ingress controller
  • Create an Ingress routing a hostname to the web Service
  • Reach the app through the Ingress with the correct Host header
  • (Bonus) Add a NetworkPolicy and reason about its effect

Validation: curl -H "Host: app.local" http://localhost/ returns the app.

🏆 Quest Rewards & Achievements

🎖️ Badges Earned:

  • 🏆 Gatekeeper - You master Services and Ingress
  • 🧭 Pathfinder - You understand cluster DNS and discovery

🛠️ Skills Unlocked:

  • Service Exposure - ClusterIP, NodePort, and LoadBalancer
  • Ingress Routing and DNS Resolution - One gate, many backends

🔓 Unlocked Quests:

  • ConfigMaps and Secrets - Configure your now-connected workloads

📊 Progression Points: +75 XP

🗺️ Next Steps in Your Journey

Continue the Main Story:

Explore Side Adventures:

Character Class Recommendations

💻 Software Developer: Continue to ConfigMaps and Secrets
🏗️ System Engineer: Revisit Pods and Workloads
🛡️ Security Specialist: Study the NetworkPolicy section above closely

📚 Resources

Official Documentation

Community Resources

Learning Materials

🤝 Quest Completion Checklist

Before marking this quest as complete, ensure you’ve:

  • ✅ Completed all primary objectives
  • ✅ Exposed a workload with a Service
  • ✅ Resolved a Service by its DNS name
  • ✅ Routed external traffic through an Ingress
  • ✅ Answered all knowledge check questions
  • ✅ Completed at least one mastery challenge

🕸️ Knowledge Graph

Structured wiki-links connect this quest to the IT-Journey knowledge graph. Open the Obsidian Graph View to explore connections.

Level hub: [[Level 1001 (9) - Kubernetes Orchestration]] Overworld: [[🏰 Overworld - Master Quest Map]] Prerequisites: [[Kubernetes Fundamentals: Container Orchestration Essentials]] · [[Kubernetes Pods and Workloads: Deployments and StatefulSets]] Unlocks: [[Kubernetes ConfigMaps and Secrets: Configuration Management Best Practices]] Obsidian docs: [[Obsidian Knowledge Graph and Wiki Links]]

🎁 Rewards

75 XP

Badges

  • 🏆 Gatekeeper - Mastered Services and Ingress
  • 🧭 Pathfinder - Understands cluster DNS and service discovery

Skills unlocked

  • 🛠️ Service Exposure (ClusterIP/NodePort/LoadBalancer)
  • 🧠 Ingress Routing and DNS Resolution

Features unlocked

  • Access to the Configuration and Secrets quest

🕸️ Quest Network

Loading quest graph…

Click a node to open the quest · ⌘/Ctrl-click for a new tab · drag to reposition · scroll to zoom.