Black Friday · 27 Nov 2026

Up to 90% off selected certifications.

One time only offer for a very precious career goal. Limited coupons, waitlist first.

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.

Sources

Log in to track progressFree account: stores only your lesson progress and quiz results.