Category Archives: 04 – Networking

Ingress

Welcome to the NZRT Wiki Podcast. Today we’re looking at Ingress.

If you’ve been working with Kubernetes, you’ve probably run into the question of how external traffic actually gets into your cluster. That’s where Ingress comes in. At its core, Ingress is a Kubernetes resource that routes incoming HTTP and HTTPS traffic to the right internal services, based on things like the hostname in the request or the URL path. One important thing to know upfront is that Ingress doesn’t work on its own. You need something called an Ingress Controller running in your cluster, and at NZRT we use the nginx-ingress controller for that.

So why use Ingress at all? To understand that, it helps to compare it with the alternative, which is a LoadBalancer Service. If you compare the two side by side, you see some important differences across five areas. First, protocol support. A LoadBalancer Service works at the TCP and UDP level, meaning it can handle almost any kind of traffic. Ingress, on the other hand, is HTTP and HTTPS only. Second, SSL termination. A LoadBalancer Service doesn’t handle SSL for you, but Ingress does. Third and fourth, routing. A LoadBalancer Service has no concept of path-based or host-based routing, meaning it just forwards everything. Ingress gives you both, so you can send traffic to different services depending on the URL path or the hostname. And fifth, cost. This is a big practical one. With LoadBalancer Services you need one load balancer per service, which adds up quickly in cloud environments. With Ingress, you only need one load balancer for everything, and Ingress handles the routing internally. That’s a significant saving.

Now let’s look at what an actual Ingress configuration looks like at NZRT. The manifest defines an Ingress resource called nzrt-ingress, sitting in the nzrt-prod namespace. It includes a couple of annotations, which are basically extra instructions for the nginx controller. One tells nginx to rewrite the request path to a forward slash, and the other tells cert-manager, which is the tool we use for SSL certificates, to use our production Let’s Encrypt issuer when generating a certificate.

The spec section is where the real routing logic lives. It starts by declaring that this Ingress uses the nginx ingress class. Then it sets up TLS, specifying that the hostname app dot nzrtnetwork dot com should be secured, and that the certificate should be stored in a Kubernetes secret called nzrt-tls. Finally, there’s a rules section. It says that any request arriving at app dot nzrtnetwork dot com, regardless of the path, should be forwarded to a service called wordpress-service on port 80. So in plain terms, you hit the NZRT app URL in your browser, Ingress intercepts that, terminates the SSL, and hands the request off to the WordPress service inside the cluster.

That brings us to cert-manager, which handles the TLS certificate side of things. You install cert-manager by applying a single manifest file from the cert-manager releases page. Once it’s running, it watches for Ingress resources that reference a cluster issuer, and it automatically requests and renews certificates from Let’s Encrypt on your behalf. You don’t have to touch the certificate manually.

To check on the status of a certificate, you run a command that lists all certificates in the nzrt-prod namespace. If you want more detail on a specific one, you describe the nzrt-tls certificate in that same namespace, and Kubernetes gives you a full breakdown including whether the certificate was issued successfully, when it expires, and any events or errors that occurred during the issuance process. If something goes wrong with your SSL setup, that describe output is usually the first place you look.

To tie this all together, the flow works like this. A user visits app dot nzrtnetwork dot com. DNS resolves that to the single load balancer sitting in front of your cluster. The load balancer passes the request to your nginx Ingress controller. The controller checks its rules, sees that the hostname matches, terminates the TLS using the certificate stored in the nzrt-tls secret, and forwards the plain HTTP request to the wordpress-service inside the cluster. All of that happens transparently, and you only needed one load balancer to make it work across however many services you want to add in future.

If you want to go deeper on any of this, the related topics in the wiki cover Networking Overview, Services, and SSL and DNS, which will give you the full picture of how all these pieces connect.

That’s it for this episode of the NZRT Wiki Podcast. Thanks for listening.

Networking Overview

Welcome to the NZRT Wiki Podcast. Today we’re looking at Networking Overview.

Kubernetes networking is the system that connects everything inside your cluster — pods talking to other pods, services providing stable endpoints, and external traffic finding its way in. If you’ve ever wondered how all those moving pieces actually reach each other, this episode walks you through it.

Let’s start with the core networking model, because Kubernetes makes some strong guarantees here that are worth understanding upfront. First, every pod gets its own unique IP address that is valid across the entire cluster. Not just within a node — across the whole cluster. Second, any pod can communicate directly with any other pod without going through network address translation, which you might know as NAT. Third, nodes can also reach any pod directly without NAT. And finally, pod IP addresses are never masqueraded — meaning what you see is what you get, no hidden remapping happening underneath. These four rules together form what’s called the Kubernetes network model, and every networking plugin you install has to honour them.

Now, let’s talk about how traffic actually flows from the outside world into your application. Picture this as a journey with a few stops. It starts with an external client — that’s someone’s browser, a mobile app, whatever is making a request from outside the cluster. That request first hits what’s called an Ingress Controller. In this setup the Ingress Controller is running nginx. The Ingress Controller is the gatekeeper — it reads your routing rules and decides where to send the traffic next. From there, the request moves to a Service. Services in Kubernetes have what’s called a ClusterIP, which is a stable internal address that doesn’t change even if the pods behind it do. Think of the Service as a reliable middleman. Finally, the request lands at the actual Pod — the container running your application. So the journey is: external client, then Ingress Controller, then Service, then Pod. Four hops, clean and predictable.

Next up is the CNI, which stands for Container Network Interface. This is the plugin layer that actually implements the network model we just described. Kubernetes doesn’t hard-code a single networking solution — instead it lets you choose a CNI plugin that suits your needs. There are four common options you’ll encounter. The first is Flannel, which is simple to set up and uses an overlay network — a good starting point if you want something that just works without a lot of configuration. The second is Calico, which gives you support for network policies and BGP routing, making it a strong choice when you need fine-grained control over which pods can talk to which. The third is Cilium, which is eBPF-based and gives you advanced observability — if you need deep visibility into your network traffic and performance, Cilium is worth a look. The fourth is Weave Net, which is known for easy setup and comes with encrypted overlay networking out of the box, so your pod-to-pod traffic is protected without extra configuration.

Choosing the right CNI depends on your priorities — simplicity, policy control, observability, or security. Most production clusters end up on Calico or Cilium, but Flannel and Weave Net are perfectly valid for smaller or simpler environments.

Now let’s cover DNS, because once pods and services exist, you need a way to find them by name rather than memorising IP addresses. Kubernetes handles this through CoreDNS, which runs inside the cluster and answers name lookups automatically. Services get a DNS name that follows a pattern: the service name, then the namespace it lives in, then the suffix svc.cluster.local. So if you have a service called api in a namespace called production, you can reach it at api.production.svc.cluster.local. Pods also get DNS names, though they’re used less often. A pod’s DNS name uses its IP address with dashes instead of dots, followed by the namespace, then pod.cluster.local. The important thing to know is that CoreDNS makes service discovery automatic — your application code can use a stable DNS name rather than hardcoding IPs that might change.

To wrap up, here’s the big picture. Every pod has its own IP, pods talk to each other freely without NAT, and the network model is enforced by whichever CNI plugin you choose. External traffic enters through an Ingress Controller, passes through a Service, and reaches your Pod. CoreDNS keeps name resolution working so everything can find everything else by name. If you want to go deeper, the related topics to explore next are Services, Ingress, and Services and DNS — each of those builds directly on what we’ve covered here.

That’s it for this episode of the NZRT Wiki Podcast. Thanks for listening.

Services Dns

Welcome to the NZRT Wiki Podcast. Today we’re looking at Services & DNS.

Let’s start with the basics. Inside a Kubernetes cluster, CoreDNS is the engine that handles automatic DNS resolution. That means when a service or a pod needs to find another service or pod by name, CoreDNS is the one doing the lookup behind the scenes.

Now, DNS names in the cluster follow a predictable pattern depending on what you’re trying to reach and where you’re reaching from. There are four main formats to know. First, if you’re looking up a service from within the same namespace, you can just use the service name on its own — short and simple. Second, if you’re crossing into a different namespace, you add the namespace after the service name, separated by a dot. Third, if you want the full, unambiguous address — what’s called a Fully Qualified Domain Name — you build it out as the service name, then the namespace, then the suffix “svc.cluster.local”. And fourth, pods themselves get a DNS name too, built from the pod’s IP address with dashes instead of dots, followed by the namespace and then “pod.cluster.local”. A real example of a fully qualified service name would look like: wordpress-service dot nzrt-prod dot svc dot cluster dot local.

Next up, testing DNS resolution. The wiki shows two ways to do this. The first approach launches a temporary debug pod using a minimal image called busybox, runs an nslookup command against the wordpress-service inside the nzrt-prod namespace, and then automatically removes itself when done. The second approach skips creating a new pod altogether — instead, you jump directly into a pod that’s already running and fire the nslookup from inside it, this time using the cross-namespace format with the namespace included in the name.

Now let’s talk about headless services, because these work a little differently. A normal service gives you a single stable IP address that load-balances traffic across your pods. A headless service, by contrast, has no cluster IP at all — and that’s intentional. When you query a headless service, you get back the actual IP addresses of the individual pods behind it. This is particularly useful for StatefulSets, where each pod needs its own stable, predictable DNS name.

In the Nextcloud example from the wiki, you’d have two pods addressable individually. The first would be nextcloud-0 dot nextcloud dot nzrt-prod dot svc dot cluster dot local, and the second would be nextcloud-1 with the same suffix. Each pod is reachable directly by name, which matters a lot for stateful applications where pod identity is important.

The configuration for a headless service is straightforward. You define it as a standard Kubernetes service, give it the name “nextcloud” in the nzrt-prod namespace, set the cluster IP field explicitly to the word “None” — that’s what makes it headless — point the selector at pods with the app label of nextcloud, and expose port 80.

Finally, if you ever need to inspect or troubleshoot the CoreDNS configuration itself, the wiki shows a command that retrieves the CoreDNS config map from the kube-system namespace and prints it out in full. This is handy if you’re chasing a DNS issue at the cluster level and need to see exactly how CoreDNS is configured.

For more context, the related topics in the wiki are Networking Overview, Services, and StatefulSets — worth reading alongside this one if you want the full picture.

That’s it for this episode of the NZRT Wiki Podcast. Thanks for listening.