Back to blog

Kubernetes Networking Essentials: Services, Ingress, and NetworkPolicies

February 18, 2026 10 min read Kubexer Team
NetworkingServicesIngressNetworkPolicy

Kubernetes networking has a reputation for being opaque, but most of it reduces to three layers: Services for internal routing, Ingress for HTTP entry, and NetworkPolicies for segmentation. Understand those and you can reason about how traffic flows through your cluster.

The flat network model

Kubernetes assumes a flat network: every Pod gets its own IP and can, by default, reach every other Pod without NAT. That simplicity is powerful but also means everything can talk to everything until you say otherwise. The three layers below build structure and control on top of that flat base.

Services: stable routing inside the cluster

Pod IPs churn; Services give you a durable address. The type determines reach:

  • ClusterIP (default) — reachable only inside the cluster. The backbone of service-to-service traffic.
  • NodePort — opens a port on every node; useful for quick external access and bare-metal setups.
  • LoadBalancer — provisions a cloud load balancer in front of the Service.
  • ExternalName — a DNS alias to an external host, no proxying.
apiVersion: v1
kind: Service
metadata:
  name: orders
spec:
  type: ClusterIP
  selector:
    app: orders
  ports:
    - port: 80
      targetPort: 8080

Other Pods reach it by DNS: orders.default.svc.cluster.local, or just orders within the same namespace.

Ingress: HTTP routing at the edge

Exposing one LoadBalancer per Service is expensive and crude. Ingress defines host- and path-based HTTP routing through a single entry point, served by an Ingress controller (NGINX, Traefik, or a cloud controller) that you must install — the Ingress object alone does nothing without one.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /orders
            pathType: Prefix
            backend:
              service:
                name: orders
                port:
                  number: 80
          - path: /catalog
            pathType: Prefix
            backend:
              service:
                name: catalog
                port:
                  number: 80
  tls:
    - hosts:
        - shop.example.com
      secretName: shop-tls

One hostname, multiple backends, TLS terminated at the edge. The ingressClassName must match an installed controller.

NetworkPolicies: turning off the open door

By default any Pod can reach any other Pod. NetworkPolicies let you allow-list traffic — but only if your CNI plugin enforces them (Calico, Cilium, and others do; some basic plugins ignore them entirely).

A NetworkPolicy is additive and selector-based. The moment a Pod is selected by any policy, it switches from "allow all" to "deny all except what is allowed". A common first step is to default-deny ingress in a namespace:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
    - Ingress

Then allow only what should talk. Here the orders Pods accept traffic only from web Pods on port 8080:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web-to-orders
spec:
  podSelector:
    matchLabels:
      app: orders
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: web
      ports:
        - protocol: TCP
          port: 8080

Debugging connectivity

When traffic does not flow, work outside-in:

  1. kubectl get endpoints orders — is the Service selecting any Pods?
  2. kubectl get ingress and the controller logs — is the route registered?
  3. kubectl describe networkpolicy — is a policy silently dropping the traffic?
  4. Exec into a Pod and curl the Service DNS name to isolate the layer.

Seeing the topology

Networking bugs are usually relationship bugs — a selector that does not match, an Ingress pointing at the wrong Service, a NetworkPolicy that is stricter than you remember. Browsing Services, Ingresses, and NetworkPolicies together in Kubexer makes those mismatches obvious, so you spend less time guessing which layer dropped the packet.

Wrapping up

Services route, Ingress exposes, NetworkPolicies segment. Start permissive while you learn the flow, then tighten with default-deny policies once you understand who needs to talk to whom. Verify endpoints first — most "networking" problems are really selector problems.