Home › CKA practice tasks › Expose internal and LoadBalancer Services
CKA · Services & Networking

Expose a Deployment with ClusterIP and LoadBalancer Services

Deployment `portal` in namespace `public-web` has two healthy nginx replicas listening on port 80. A LoadBalancer implementation and an address pool are already configured. Pod `check` is available for internal HTTP tests. The assigned external address is a lab-only address reachable from this terminal, not a public Internet address.

Live lab access

This task description is public. Its live lab requires full access; six other CKA labs are available in Free Practice with AI Lab Coach.

Create an account to continue →

Explore the six free labs with AI Lab Coach →

Read the brief on any device. Use a desktop or laptop for the terminal lab. Nothing starts until you choose Start.

The task

Deployment portal in namespace public-web has two healthy nginx replicas listening on port 80. A LoadBalancer implementation and an address pool are already configured. Pod check is available for internal HTTP tests. The assigned external address is a lab-only address reachable from this terminal, not a public Internet address.

Requirements
1. Create ClusterIP Service portal-internal selecting app=portal, with TCP port 80 targeting port 80.
2. Create LoadBalancer Service portal-public with the same selector and port mapping.
3. Ensure the public Service has both ready application endpoints and an assigned external IP.
4. Verify HTTP access through the internal Service from Pod check, and through the assigned external IP from this terminal.

Use the provided load-balancer infrastructure. Do not assign externalIPs manually or patch the Service status.

Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster. The external part needs a LoadBalancer implementation (a cloud provider, or something like MetalLB with an address pool); without one, the internal steps still work.

ClusterIP, NodePort, LoadBalancer: three layers, and who hands out the external IP

The three Service types stack rather than compete. Every LoadBalancer Service also has a cluster IP and, by default, a node port; the external address is an extra layer on top. Kubernetes itself does not ship a load balancer: an implementation watches LoadBalancer Services, provides an address, and the address is published in status.loadBalancer.ingress. Knowing which layer you are testing tells you which component to blame when a request fails.

client outside ──→ external IP (from the implementation's pool)
                     └─→ node port on any node (allocated by default)
Pod inside     ──→ cluster IP : port
                     └─→ EndpointSlice: ready Pod IPs : targetPort

1. Create a backend and one LoadBalancer Service

kubectl create namespace prepium-tutorial
kubectl -n prepium-tutorial create deployment gallery --image=nginx:1.27-alpine --replicas=2
kubectl -n prepium-tutorial expose deployment gallery --name=gallery-lb \
  --type=LoadBalancer --port=8080 --target-port=80
kubectl -n prepium-tutorial get svc gallery-lb

The Service listens on 8080 and forwards to container port 80, so port and targetPort are visibly different things here. The output has a CLUSTER-IP and an EXTERNAL-IP column, and -o jsonpath='{.spec.ports[0].nodePort}' reveals the node port allocated underneath. If EXTERNAL-IP reads <pending>, wait a minute; if it never changes, nothing in the cluster is fulfilling LoadBalancer Services.

2. See where the external address comes from

kubectl -n prepium-tutorial wait --for=jsonpath='{.status.loadBalancer.ingress}' svc/gallery-lb --timeout=120s
kubectl -n prepium-tutorial get svc gallery-lb -o jsonpath='{.status.loadBalancer.ingress[0].ip}{"\n"}'
kubectl -n metallb-system get ipaddresspools.metallb.io

The last command applies only if MetalLB is your implementation. MetalLB hands out addresses from IPAddressPool objects (API metallb.io/v1beta1) and, in layer 2 mode, an L2Advertisement makes them reachable. The address you received should sit inside one of those pools. Notice that you never typed it: the status field is written by the implementation, not by you. spec.externalIPs is a different, manual mechanism that Kubernetes does not manage.

3. Check the backends before testing traffic

kubectl -n prepium-tutorial get endpointslices -l kubernetes.io/service-name=gallery-lb -o wide
kubectl -n prepium-tutorial get svc gallery-lb -o jsonpath='{.spec.selector}{"\n"}'
kubectl -n prepium-tutorial get pods --show-labels -o wide

The EndpointSlice should list both Pod IPs with port 80, each marked ready, and the selector must match labels on those Pods. An external IP proves only that the implementation did its job; it says nothing about whether the selector matches any ready Pods.

4. Test from inside, then from outside

kubectl -n prepium-tutorial run probe --rm -i --image=busybox:1.36 --restart=Never -- \
  wget -qO- -T 3 http://gallery-lb.prepium-tutorial.svc.cluster.local:8080
LB_IP=$(kubectl -n prepium-tutorial get svc gallery-lb -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl -s -m 5 "http://$LB_IP:8080" | head -n 4

The first request uses DNS and the cluster IP; the second leaves through the external address from a machine that can route to the pool. If the inside test passes and the outside one fails, the problem is the address advertisement or the network path, not the Pods.

Common mistakes

Example checkEvidence
Address assigned by the implementationstatus.loadBalancer.ingress holds an IP from the pool
Backends are liveEndpointSlice with label kubernetes.io/service-name lists ready endpoints
Internal path worksIn-cluster request to the Service DNS name and port returns the page
External path worksRequest to the external IP on the Service port returns the page

Cleanup: kubectl delete namespace prepium-tutorial. References: Service, Create an External Load Balancer, EndpointSlices, MetalLB configuration. Next, try NodePort Services or path-based Ingress routing.

Difficulty
Medium · 7 minutes target
Domain
Services & Networking
Grading
Live checks · partial credit

Practice scope

This additional curriculum lab is available in single-task practice with the existing 12-minute limit. Its alternate scenario also appears in one of the two mixed curriculum mocks. The first three 17-task mocks keep their original task sets. Hints, an explained solution and requirement-by-requirement feedback are available in the lab.

Browse CKA practice tasks →