In Unit 2, you learned that Services automatically get DNS names, allowing applications to connect using names like backend-svc instead of IP addresses. You saw how CoreDNS resolves these names to ClusterIP addresses, enabling loose coupling between your application components. But that was just the foundation.
In this lesson, you'll tackle the advanced service discovery scenarios that arise in real production environments: connecting to Services in different namespaces, integrating with external systems outside your cluster, and understanding why some IPs remain stable while others constantly change. These patterns are essential when you're building distributed systems that span multiple namespaces, hybrid cloud architectures, or migrating legacy applications into Kubernetes.
So far, you've probably worked within a single namespace — typically default. But production Kubernetes environments use multiple namespaces to isolate different teams, applications, or environments. When your frontend Pod in the web namespace needs to connect to a backend Service in the api namespace, the simple service name won't work. Kubernetes DNS uses namespace-scoped resolution by default, so backend-svc only resolves within your current namespace. For cross-namespace access, you need to use the Fully Qualified Domain Name (FQDN).
The FQDN pattern is <service-name>.<namespace>.svc.cluster.local. If you have a Service called database-svc in the data namespace, you can access it from any namespace using database-svc.data.svc.cluster.local, or the shorter form database-svc.data. Let's see this in action with a concrete example.
First, create two namespaces to simulate a multi-tier application:
Now create a backend service in the backend namespace. Save this as deployment-backend.yaml:
Not all services you need to connect to run inside your Kubernetes cluster. You might have a legacy database on a physical server, a managed database service from your cloud provider, or an external API you depend on. You could hardcode these external addresses in your application configuration, but that loses the benefits of DNS-based service discovery — you want your application to connect using a service name regardless of whether the backing resource is inside or outside the cluster. Kubernetes supports this through Services without selectors and manually defined Endpoints.
When you create a Service without a selector field, Kubernetes doesn't automatically create Endpoints for it. Instead, you manually create an Endpoints object with the same name as the Service, specifying the external IP addresses and ports you want to route to. From your application's perspective, this looks exactly like any other Service — you connect using the Service name, and Kubernetes routes the traffic to the external resource.
Let's create a Service that points to an external database. Save this as service-external-db.yaml:
Notice there's no selector in this Service definition. Apply it:
Check the endpoints — there should be none:
Now manually create the Endpoints object. Save this as endpoints-external-db.yaml:
One of the most important architectural concepts in Kubernetes is the contrast between stable ClusterIP addresses and ephemeral Pod IPs. When you create a Service, it gets assigned a ClusterIP that remains constant for the Service's lifetime — it never changes unless you delete and recreate the Service. Pod IPs, however, are temporary. Every time a Pod restarts, is rescheduled to a different node, or gets replaced by its controller, it receives a brand new IP address. This is why you must never hardcode Pod IPs in your application configuration.
Let's demonstrate this stability difference. Check the current ClusterIP of the backend Service:
Note the ClusterIP (10.96.145.67). Now check the Pod IPs:
The Pods have IPs like 10.244.1.10 and 10.244.1.11. Now simulate a Pod failure by deleting one:
The Deployment controller immediately creates a replacement. Wait a few seconds and check again:
You've now mastered the advanced service discovery patterns essential for production Kubernetes environments. You learned how to access Services across namespaces using FQDNs, integrate external resources using manual Endpoints, and understand the architectural distinction between stable ClusterIPs and ephemeral Pod IPs. These patterns enable you to build distributed systems that span multiple namespaces, connect to legacy infrastructure outside your cluster, and maintain loose coupling even as Pods constantly come and go.
In the upcoming practice exercises, you'll apply these concepts hands-on: accessing Services from different namespaces, connecting to external databases using manual Endpoints, observing ClusterIP stability during Pod disruptions, and implementing cross-namespace communication in a multi-tier application. These exercises will prepare you for real-world scenarios where applications must discover services across namespace boundaries, integrate with external systems, and remain resilient to the constant infrastructure changes that define cloud-native environments.
