Free lesson · CKAD Prep Program · Module 6: Services and networking
Build Apps That Survive NetworkPolicies
Policy-locked namespaces reject whatever nobody declared. Apps survive by declaring everything: dependencies, ports, DNS, and the labels selectors will match.
12 min reading
Objectives
- List every connection your app needs before lockdown, including DNS
- Declare the labels the policy will select on from day one
- Test connectivity from allowed plus denied identities after each rule
- Debug a policy-blocked app back to the missing allow entry
Why this matters
The classic policy casualty is a correct app deployed into a locked namespace it never met in dev. Connections die silently (timeouts, not errors), and the app gets blamed for the platform's new rules. Developing policy-aware means enumerating flows first and labeling for selectors always.
Concepts
Enumerate before you code: database host plus port, cache, queues, external APIs, metrics scrapes, and DNS (UDP and TCP 53 to kube-dns). Every entry becomes an allow rule or an outage; there is no third outcome. Labels are the contract: app, role and tier labels chosen at authoring time are what policies select on later, so label every pod as if a policy already exists.
Egress declares destinations by peer kind: podSelector for cluster neighbors, namespaceSelector for platform services, ipBlock for the outside world. Debugging is two-sided by construction: success from the allowed identity plus timeout from a denied one proves the rule instead of the absence of breakage.
Worked example
Checkout app needs ledger on 8443, Postgres on 5432, DNS, nothing else:
# app pods carry the labels policies will select
metadata: { labels: { app: checkout, tier: backend } }
# the allow entries its developer declares alongside the deploy
egress:
- to: [{ podSelector: { matchLabels: { app: ledger } } }]
ports: [{ protocol: TCP, port: 8443 }]
- to: [{ podSelector: { matchLabels: { app: postgres } } }]
ports: [{ protocol: TCP, port: 5432 }]
- to:
- namespaceSelector: {}
podSelector: { matchLabels: { k8s-app: kube-dns } }
ports: [{ protocol: UDP, port: 53 }, { protocol: TCP, port: 53 }]Ship the flow list with the app: reviewers match entries to code imports, and the policy author copies rather than guesses. Test with curl from the app pod (works) and a label-less debug pod (times out).
Exam notes
Metrics endpoints need explicit allows or scraping dies with the lockdown: declare the scraper's identity too. Health probes from kubelet bypass policies (node-to-pod is not pod-to-pod), so passing probes with dead app traffic means policy, not app. And DNS over TCP matters for large answers: allowing only UDP 53 fails exactly the biggest lookups.
Quick check
A 4-question self-check. Your answers stay on your device, are never stored or sent. Only a passing score (for example 3 of 4) is saved, and only to unlock lesson progress: at least 3 correct is required before a lesson counts as complete. It never counts toward any certification assessment.
Lesson feedback
No published feedback yet.
Log in and complete the lesson to leave feedback.
Exercise
List every connection a fictional three-tier app needs (tiers plus database plus DNS), label the pods for selection, and write the egress entries. Show the two-sided test with expected results for one allowed and one denied flow.
Pass criteria
Flow list complete including DNS and metrics if present; labels support the selectors; entries cover all flows; two-sided test shows success plus timeout correctly.