Services provide stable IP addresses for ephemeral Pods, Ingress controllers route HTTP/S domain traffic at Layer 7, and NetworkPolicies act as Pod-level firewalls. In this episode, we build production manifests for all three.
TL;DR (Quick Summary)#
- Expose Service:
kubectl expose deployment web-api --port=80 --target-port=8080 --type=ClusterIP - Create Ingress:
kubectl create ingress web-ingress --rule="app.example.com/api*=api-service:80" - NetworkPolicy Default Deny: Block all ingress traffic to a namespace unless explicitly allowed.
1. Kubernetes Traffic Flow Architecture#
graph TD
Client["External HTTP Client"] -->|app.example.com| Ingress["Ingress Controller (L7)"]
Ingress -->|Path /api| ServiceA["Service: api-service (L4 ClusterIP)"]
Ingress -->|Path /web| ServiceB["Service: web-service (L4 ClusterIP)"]
ServiceA -->|Selector app=api| PodA["Pod: API Container"]
ServiceB -->|Selector app=web| PodB["Pod: Web Container"]
PodA <== NetworkPolicy Firewall Rule ==> PodB
2. CKAD Terminal Hands-on Scenarios#
Scenario A: Expose Workload via Service#
Create a Deployment named backend running nginx on port 80, then expose it as a NodePort service named backend-svc listening on port 8080 and mapping to target port 80.
# 1. Create deployment
kubectl create deployment backend --image=nginx:1.25-alpine --replicas=2
# 2. Expose NodePort service
kubectl expose deployment backend \
--name=backend-svc \
--type=NodePort \
--port=8080 \
--target-port=80Verify endpoints attached to the service:
kubectl get endpoints backend-svcScenario B: Create HTTP Ingress Path Routing#
Create an Ingress resource named app-ingress that routes requests for host myapp.test:
- Path
/analytics-> Serviceanalytics-svc(port 80) - Path
/store-> Servicestore-svc(port 8080)
app-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.test
http:
paths:
- path: /analytics
pathType: Prefix
backend:
service:
name: analytics-svc
port:
number: 80
- path: /store
pathType: Prefix
backend:
service:
name: store-svc
port:
number: 8080Scenario C: Enforce Zero-Trust NetworkPolicy Isolation#
Create a NetworkPolicy named db-netpol inside namespace secure-ns that allows incoming traffic on port 5432 to Pods labeled role=db ONLY from Pods labeled role=api-backend.
db-netpol.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-netpol
namespace: secure-ns
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: api-backend
ports:
- protocol: TCP
port: 54323. NetworkPolicy Isolation Rules Reference#
| Rule Purpose | policyTypes | Selector Match | Result |
|---|---|---|---|
| Default Deny All Ingress | [Ingress] | {} | Drops ALL incoming traffic to all pods in namespace |
| Default Deny All Egress | [Egress] | {} | Drops ALL outgoing traffic from all pods in namespace |
| Allow Specific Namespace | [Ingress] | namespaceSelector | Accepts traffic ONLY from matching namespace labels |
Summary & Next Steps#
In this episode, we covered:
- Exposing workloads via ClusterIP and NodePort Services.
- Configuring Layer 7 HTTP path routing using Ingress manifests.
- Restricting pod-to-pod network traffic using declarative NetworkPolicies.
In CKAD Episode 5: Storage & Persistent Workloads, we will provision PersistentVolumes, PersistentVolumeClaims, and StatefulSet storage!

