Services & Networking is one of the most practical domains on the Certified Kubernetes Application Developer (CKAD) exam — and one where candidates lose easy points under time pressure. The tasks are rarely conceptually hard, but they reward muscle memory: knowing exactly which Service type to reach for, how to wire a NetworkPolicy without locking yourself out, and how to expose a Deployment through Ingress in under two minutes.
This guide walks through everything in the CKAD Services & Networking domain from a practitioner’s perspective. You’ll get working YAML, the imperative kubectl shortcuts that save time on exam day, and the troubleshooting moves that turn a broken connection into a green checkmark.
What the CKAD Tests in Services & Networking
The “Services & Networking” domain accounts for roughly 20% of the CKAD exam. The official curriculum expects you to:
- Demonstrate a basic understanding of NetworkPolicies
- Provide and troubleshoot access to applications via Services
- Use Ingress rules to expose applications
In plain terms: you need to make a Pod reachable, control who can talk to it, and route external HTTP traffic to it. Everything below maps directly to those three abilities.
Before going further, remember the golden rule of every CKAD networking task: a Service finds Pods by label selector, not by name. If a Service has zero endpoints, the selector almost always doesn’t match the Pod labels. Burn that into memory now and you’ll save yourself half your troubleshooting time.
Kubernetes Services: The Four Types
A Service is a stable network identity (a virtual IP and DNS name) that load-balances traffic across a dynamic set of Pods. Pods are ephemeral — they come and go with rolling updates and rescheduling — so you never connect to a Pod IP directly. You connect to the Service.
| Service Type | What it does | Typical CKAD use |
|---|---|---|
ClusterIP | Internal-only virtual IP (the default) | Service-to-service inside the cluster |
NodePort | Opens a static port (30000–32767) on every node | Quick external access for testing |
LoadBalancer | Provisions an external load balancer (cloud) | Production external access |
ExternalName | Maps the Service to an external DNS name via CNAME | Aliasing an external dependency |
For the exam, you live mostly in ClusterIP and NodePort territory. LoadBalancer and ExternalName appear less often, but you should recognize them.
Creating a Service the Fast Way
Typing a Service YAML by hand wastes precious minutes. Use the imperative generators instead.
Expose an existing Deployment as ClusterIP:
kubectl expose deployment web --port=80 --target-port=8080 --name=web-svc
--port is the port the Service listens on; --target-port is the container port it forwards to. If you omit --target-port, it defaults to --port.
Create a ClusterIP Service for a Pod in one shot:
kubectl run nginx --image=nginx --port=80 --expose
Generate a NodePort Service:
kubectl expose deployment web --type=NodePort --port=80 --name=web-np
You can’t set a specific nodePort with kubectl expose directly, so if a task demands a fixed port like 30080, generate the YAML and edit it:
kubectl expose deployment web --type=NodePort --port=80 --dry-run=client -o yaml > svc.yaml
Then add nodePort: 30080 under the port entry. The full YAML looks like this:
apiVersion: v1
kind: Service
metadata:
name: web-np
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 30080
Verifying a Service Actually Works
The single most useful command in this entire domain:
kubectl get endpoints web-svc
If you see Pod IPs listed, your selector matches and the Service is wired correctly. If you see <none>, the selector is wrong — compare it against the Pod labels:
kubectl get pods --show-labels
kubectl describe svc web-svc | grep -i selector
To test connectivity from inside the cluster without leaving the terminal, spin up a throwaway client:
kubectl run tmp --image=busybox --rm -it --restart=Never -- wget -qO- web-svc:80
The --rm flag deletes the Pod when you exit, keeping your namespace clean.
Service DNS: Know the Naming Convention
Kubernetes DNS gives every Service a predictable name. On the exam you’ll often need to reference a Service from another namespace, and the FQDN pattern is:
<service-name>.<namespace>.svc.cluster.local
So a Service named db in namespace data is reachable as:
db— from a Pod in the same namespacedb.data— from any namespace (short form)db.data.svc.cluster.local— fully qualified
If an app in namespace web can’t reach db in namespace data, check that it’s using db.data, not just db. This is a classic exam trap.
Ingress: Routing External HTTP Traffic
A Service of type NodePort or LoadBalancer exposes a single app on a port. Ingress is smarter — it routes external HTTP(S) traffic to multiple Services based on hostname and path, all behind one entry point. Ingress requires an Ingress controller (NGINX, Traefik, etc.) to actually do the routing; the Ingress resource is just the rules.
A Practical Ingress Example
Say you have two Services — api-svc and web-svc — and you want path-based routing under app.example.com:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: web-svc
port:
number: 80
Key fields the exam cares about:
pathType— almost alwaysPrefixfor CKAD tasks.Exactmatches the path literally;Prefixmatches/apiand everything beneath it.backend.service.port.number— this is the Service port, not the container port. A frequent mistake is putting the container’stargetPorthere.host— optional. Omit it to match all hostnames.
Generating Ingress Imperatively
Newer kubectl versions support an Ingress generator, which is a huge time-saver:
kubectl create ingress app-ingress \
--rule="app.example.com/api*=api-svc:80" \
--rule="app.example.com/*=web-svc:80"
The * at the end of the path sets pathType: Prefix automatically. Always verify with kubectl get ingress and kubectl describe ingress app-ingress — the describe output shows whether the backend Services resolved.
NetworkPolicy: Controlling Pod-to-Pod Traffic
By default, every Pod can talk to every other Pod in a Kubernetes cluster. A NetworkPolicy changes that by selecting Pods and declaring which ingress (incoming) and egress (outgoing) traffic is allowed. NetworkPolicies are additive and require a CNI plugin that enforces them (Calico, Cilium, etc.) — on a cluster without one, policies are silently ignored.
Three rules to internalize before you touch a single YAML:
- NetworkPolicies are allow-lists. Once a Pod is selected by any policy for a direction, everything not explicitly allowed in that direction is denied.
- A policy with an empty
podSelector: {}selects every Pod in the namespace. policyTypesdeclares which directions the policy governs. If you specifyIngressonly, egress is untouched.
Default-Deny: The Most Common Exam Task
A frequent CKAD ask is “deny all incoming traffic to Pods in namespace X.” That’s this:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: secure
spec:
podSelector: {}
policyTypes:
- Ingress
The empty podSelector selects all Pods; the absence of any ingress rule means nothing is allowed in. To lock down both directions, add Egress to policyTypes.
Allowing Specific Traffic
Now the realistic version: allow Pods labeled app: frontend to reach Pods labeled app: backend on port 8080, and nothing else.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
namespace: secure
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Read it top to bottom: this policy applies to backend Pods, governs ingress, and allows traffic from frontend Pods on TCP 8080.
The namespaceSelector vs podSelector Trap
This is where candidates lose points. Inside a from block, the indentation determines the logic:
# AND: from Pods labeled role=client THAT ARE IN namespaces labeled team=web
ingress:
- from:
- namespaceSelector:
matchLabels:
team: web
podSelector:
matchLabels:
role: client
# OR: from any Pod in namespaces labeled team=web, OR any Pod labeled role=client
ingress:
- from:
- namespaceSelector:
matchLabels:
team: web
- podSelector:
matchLabels:
role: client
The difference is a single dash. In the first, namespaceSelector and podSelector are in the same list item (logical AND). In the second, they’re separate list items (logical OR). When a task says “from Pods labeled X in namespace Y,” that’s an AND — keep them under one dash.
Don’t Forget DNS in Egress Policies
If you write a default-deny egress policy, your Pods can no longer resolve DNS, and every outbound connection breaks with a name-resolution error. You almost always need to explicitly allow egress to the cluster DNS:
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
This is a favorite “gotcha” — a task asks you to restrict egress, your policy looks correct, but the app times out because it can’t reach kube-dns.
Troubleshooting Workflow for Exam Day
When a connectivity task fails, work through this checklist in order. It catches the overwhelming majority of issues:
- Endpoints first.
kubectl get endpoints <svc>— no endpoints means a selector mismatch. - Compare labels.
kubectl get pods --show-labelsagainstkubectl describe svc <svc>. - Check ports. Is
targetPortthe actual container port? Is the Pod listening on it? - Test internally.
kubectl run tmp --image=busybox --rm -it --restart=Never -- wget -qO- <svc>:<port>. - Look for NetworkPolicies.
kubectl get netpol -A— a default-deny somewhere may be blocking you. - Verify cross-namespace DNS. Use
<svc>.<namespace>form, not just<svc>. - For Ingress, confirm the backend Service exists and the controller is running.
Time-Saving Aliases and Shortcuts
The CKAD is time-constrained. Set these up in the first 60 seconds:
alias k=kubectl
export do="--dry-run=client -o yaml"
export now="--force --grace-period=0"
Then everything becomes faster:
k expose deploy web --port=80 $do > svc.yaml
k create ingress web --rule="/*=web:80" $do > ing.yaml
Also memorize the explain command for when you blank on a field:
kubectl explain networkpolicy.spec.ingress --recursive
This prints the entire schema for the ingress block — invaluable when you can’t remember whether it’s from or source.
Putting It All Together: A Realistic Scenario
A complete exam-style task might read: “In namespace shop, expose the catalog Deployment internally on port 80, route external traffic to it at shop.local/catalog, and ensure only Pods labeled tier: gateway can reach it.”
Your solution, end to end:
# 1. Internal Service
kubectl -n shop expose deployment catalog --port=80 --target-port=8080 --name=catalog
# 2. Ingress
kubectl -n shop create ingress catalog --rule="shop.local/catalog*=catalog:80"
# 3. NetworkPolicy restricting access
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: catalog-allow-gateway
namespace: shop
spec:
podSelector:
matchLabels:
app: catalog
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
tier: gateway
ports:
- protocol: TCP
port: 8080
Verify each piece: kubectl -n shop get endpoints catalog, kubectl -n shop describe ingress catalog, and a quick wget test from a tier: gateway Pod versus a non-gateway Pod.
How to Practice This Until It’s Automatic
Reading YAML is not the same as producing it under a ticking clock. The only reliable way to master Services & Networking is repetition in a real cluster: spin up Deployments, expose them every way, break the selectors on purpose, and watch endpoints disappear. Write a default-deny policy and feel the app go dark, then open it back up one rule at a time.
If you’d rather practice against realistic, exam-style scenarios with detailed explanations, the CKAD Certification Ready Mock Exam Bundle runs directly in your browser and includes hands-on networking labs that mirror the real exam’s question style. It’s a structured way to build the muscle memory this domain demands — each task comes with a breakdown of why the answer works, so you’re learning patterns, not just memorizing commands.
For the broader picture, pair this with our CKAD Exam Guide 2026 and CKAD study plan, and keep the CKAD kubectl cheat sheet open while you drill.
Frequently Asked Questions
Do I need to memorize NetworkPolicy YAML for the CKAD?
You don’t need to memorize it perfectly, but there’s no imperative generator for NetworkPolicies, so you’ll write them by hand. Memorize the skeleton — podSelector, policyTypes, ingress/egress with from/to and ports — and lean on kubectl explain networkpolicy.spec --recursive for the rest.
What’s the difference between port, targetPort, and nodePort?
port is the port the Service exposes inside the cluster. targetPort is the container port traffic is forwarded to. nodePort is the external port (30000–32767) opened on every node when the Service type is NodePort. Mixing these up is the most common Service mistake.
Why does my Service have no endpoints?
Almost always a label selector mismatch. The Service’s spec.selector must exactly match the Pod labels. Run kubectl get pods --show-labels and kubectl describe svc <name> and compare them character by character.
Will NetworkPolicies work on any cluster?
Only on clusters with a CNI plugin that enforces them, such as Calico or Cilium. On a cluster without policy enforcement, NetworkPolicy resources are accepted but have no effect. The CKAD exam environment supports them, so write them as if they’re enforced.
Is Ingress or NodePort better for exposing apps?
For real production HTTP routing, Ingress is better — it handles multiple hosts and paths behind one entry point with TLS. NodePort is fine for quick testing or non-HTTP traffic. On the exam, read the task carefully: if it mentions hostnames or paths, use Ingress; if it just says “expose on a node port,” use NodePort.
How much of the CKAD is networking?
The Services & Networking domain is about 20% of the exam. Combined with how often networking touches other tasks (you frequently expose the apps you build), it’s worth investing real practice time here.
Key Takeaways
- A Service finds Pods by label selector — check
kubectl get endpointsfirst when connectivity breaks. - Know the four Service types and the
port/targetPort/nodePortdistinction cold. - Use
kubectl exposeandkubectl create ingressto generate resources fast, then edit the YAML. - Ingress routes external HTTP by host and path; the backend port is the Service port.
- NetworkPolicies are allow-lists — once a Pod is selected, everything not allowed is denied.
- Watch the
namespaceSelectorvspodSelectorAND/OR indentation trap. - Always allow DNS egress when writing default-deny egress policies.
Master these patterns through hands-on repetition, and the Services & Networking domain becomes one of the fastest, most reliable sources of points on the entire CKAD.