One front door: Services and Ingress
- Published
- Read
- 6 minutes
- Tags
Give your application a stable address and follow a browser request through Ingress and a Service to its Pod.
Your application needs an address that survives the Pod running it.
In chapter one, you put nginx in a Pod and visited it through kubectl port-forward. That works for a quick look. For an application people need to reach, I want a front door that stays put when the tenant moves out.
A Service provides that door. Ingress routes browser traffic to it. You can add both to the Docker Desktop cluster you already created.
Pods move. The address should stay.
Each Pod has an IP address. A replacement Pod can have a different one, so sending callers directly to that IP means asking them to keep updating their address book.
A Service gives an application a stable name and, by default, an internal IP address. It finds its Pods through labels: small pieces of metadata attached to Kubernetes objects.
Think of the Service as the front door for a household. The people behind it can change without everyone who visits needing new directions. In Kubernetes, the selector on the Service says which labels its Pods must have. Kubernetes keeps the matching backend addresses up to date.
The Service you create here is reachable inside the cluster. Your browser needs a way in from outside it.
Give nginx a Service
Use the cluster from chapter one: Docker Desktop with the kind provisioner, on Windows or macOS. Stop any old port-forward command with Ctrl+C and check your context:
kubectl config use-context docker-desktop
kubectl get nodesThe Node should be Ready. Chapter one ended by deleting nginx, so recreate it now. Update nginx-pod.yaml to include a label:
apiVersion: v1
kind: Pod
metadata:
name: guide-nginx
namespace: default
labels:
app: guide-nginx
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80Apply it and wait for nginx:
kubectl apply -f nginx-pod.yaml
kubectl wait -n default --for=condition=Ready pod/guide-nginx --timeout=120sSave the following as nginx-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: guide-nginx
namespace: default
spec:
selector:
app: guide-nginx
ports:
- port: 80
targetPort: 80The selector matches the label you added to the Pod. port is where the Service accepts connections; targetPort is where nginx listens inside the Pod. Both happen to be 80.
kubectl apply -f nginx-service.yaml
kubectl get service guide-nginx -n defaultYou should see a Service named guide-nginx. It gives nginx an internal address; the next step makes it reachable from your browser.
Ingress gives visitors directions
An Ingress describes how HTTP and HTTPS requests should reach Services. A rule might say: requests for this hostname, at this path, belong at the nginx Service.
In the house analogy, the hostname is the street address. The Ingress rules tell arriving visitors which front door to use.
Those rules need an Ingress controller to put them into practice. I am using Traefik, a reverse proxy that reads the rules and forwards requests.
Docker Desktop already handles the cluster’s external networking. For the setup used here, with desktop-cloud-provider-kind:v0.7.0 and no IngressClass installed, you still need to add the Ingress controller.
Install Traefik
Install Helm, the package manager used to install Traefik. If you already use Homebrew on macOS:
brew install helmOn Windows, with WinGet:
winget install Helm.HelmIf neither package manager is available, the Helm installation page includes downloadable binaries. Reopen your terminal after installation and check helm version.
Save this as traefik-values.yaml:
providers:
kubernetesCRD:
enabled: false
kubernetesIngress:
enabled: true
nativeLBByDefault: true
ports:
websecure:
expose:
default: falseThis keeps the exercise on standard Kubernetes Ingress and plain HTTP. The nativeLBByDefault setting sends traffic through the nginx Service on its way to the Pod.
Install chart version 42.0.0, which packages Traefik 3.7.14 and requires Kubernetes 1.30 or newer:
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm upgrade --install traefik traefik/traefik --version 42.0.0 --namespace default --kube-context docker-desktop -f traefik-values.yaml --wait --timeout 5m
kubectl get ingressclass
kubectl get service traefik -n defaultExpect an IngressClass named traefik. Traefik also gets its own LoadBalancer Service: Docker Desktop’s networking makes that entry point accessible from your laptop. The nginx Service remains internal.
Add the route
Save this as nginx-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: guide-nginx
namespace: default
spec:
ingressClassName: traefik
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: guide-nginx
port:
number: 80ingressClassName selects Traefik. The rule sends requests for localhost, under /, to port 80 of the guide-nginx Service.
kubectl apply -f nginx-ingress.yaml
kubectl get ingress guide-nginx -n defaultOpen http://localhost. You should see the nginx welcome page without a port-forward process running.
The browser reaches Docker Desktop’s published HTTP port. Traffic enters through Traefik’s LoadBalancer Service, reaches Traefik, and follows the Ingress rule to the nginx Service. That Service forwards it to the Pod’s port 80.
On an internet-facing cluster, public DNS would point your hostname at the external entry point. Here, localhost brings the browser back to your own laptop. This exercise sets up local HTTP access; public DNS and TLS need their own configuration.
If the door stays shut
Check the controller and route:
kubectl get pods -n default -l app.kubernetes.io/name=traefik
kubectl describe ingress guide-nginx -n default
kubectl get service traefik -n defaultA Traefik 404 usually means the hostname or path did not match. Use http://localhost exactly: visiting 127.0.0.1 sends a different host header. A 503 can mean nginx is unavailable. Check that its Pod is ready and that the Service selector matches the Pod label:
kubectl get pod guide-nginx -n default --show-labels
kubectl describe service guide-nginx -n defaultIf the browser cannot connect at all, check that port 80 is free and the Traefik LoadBalancer has finished provisioning. To isolate host networking from routing, temporarily run:
kubectl port-forward -n default service/traefik 8080:80Visit http://localhost:8080. This still exercises Traefik and the Ingress rule, but bypasses Docker Desktop’s external entry point. If it works, investigate the LoadBalancer and host port. Stop forwarding with Ctrl+C before continuing.
Replace the tenant
With the normal http://localhost route working, delete nginx:
kubectl delete pod guide-nginx -n defaultRefresh the page. Requests will fail while the only application Pod is gone. A Service keeps the address stable; it cannot serve a page without a backend.
Recreate the Pod from the same file:
kubectl apply -f nginx-pod.yaml
kubectl wait -n default --for=condition=Ready pod/guide-nginx --timeout=120s
kubectl get pods -n default -o wideThe Pod may have a different IP. Refresh the same browser address and nginx should return. You did not change the Service or Ingress.
Keep these resources and YAML files for the next chapters. Chapter three gives them a namespace of their own; scaling follows in part four.
