Summer Sale 2026 – NPI EA (cat = Baeldung on Ops)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

1. Introduction

Kubernetes ingress is a powerful resource that allows us to manage external access to services within our Kubernetes cluster. By defining rules for routing HTTP and HTTPS traffic, ingress provides a single entry point for multiple services, reducing the complexity of managing multiple NodePorts or LoadBalancers. This becomes especially useful in production environments, where simplicity and efficiency are key.

In this tutorial, we’ll walk through setting up an ingress controller in a Kubernetes cluster and configuring ingress resources to route traffic to our services. We’ll also explore obtaining a Kubernetes ingress endpoint or IP address, which we’ll need to access our services externally.

Whether we’re running a bare-metal cluster or using a cloud provider, we’ll discuss why this is important and how it fits into the broader picture of Kubernetes networking. Let’s get started!

2. Setting up Kubernetes Ingress Controller

Ingress is an API object that manages external access to services in a Kubernetes cluster. It acts as a layer 7 (application layer) load balancer, providing HTTP and HTTPS routing from outside the cluster to services within.

Using ingress offers several advantages:

  • URL-based routing: We can route traffic to different services based on the URL path.
  • SSL/TLS termination: Ingress can handle SSL/TLS encryption, offloading this task from our services.
  • Name-based virtual hosting: We can host multiple domains on a single IP address.
  • Load balancing: Ingress can distribute incoming traffic across multiple backend services.

Unlike services, which typically expose a single service on a specific port, an ingress controller allows us to define complex routing rules. These rules might route traffic based on the URL path, the host, or even SSL/TLS settings.

There are several ingress controllers available, with the most popular ones being:

For this tutorial, we’ll continue with the NGINX ingress controller, which is commonly used across many Kubernetes environments. This is due to its mature and stable performance, extensive documentation, and strong community support.

Moreover, NGINX offers high performance, especially under heavy traffic loads, and is feature-rich. It supports SSL/TLS termination, load balancing, and various other capabilities, making it a versatile choice for different Kubernetes setups.

2.1. Installing NGINX Ingress Controller

To install the NGINX ingress controller, first, we need to deploy the NGINX ingress controller using the mandatory YAML file provided by the NGINX ingress project:

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
...
deployment.apps/ingress-nginx-controller created

Here, we set up the necessary resources in our cluster, such as Deployments, Services, and ConfigMapsThe command will create a new namespace, ingress-nginx, and deploy the ingress controller within it. Then, the controller will start watching for ingress resources across all namespaces in our cluster.

After applying the configuration, let’s verify that the ingress controller has been deployed successfully by checking the status of the pods in the ingress-nginx namespace:

$ kubectl get pods -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-controller-7f9bcb7ccf-hjksm   1/1     Running     0          2m

The STATUS column should show Running, indicating that the controller is up and running.

2.2. Configuring LoadBalancer for Ingress on Bare Metal

In most cloud environments, the NGINX ingress controller automatically provisions a LoadBalancer to handle external traffic. However, when running Kubernetes on bare metal, we need to manually configure this setup.

To expose the ingress controller externally, we first need to create a Service of the type LoadBalancer. This service will route external traffic to the ingress controller, which will then forward it to the appropriate services based on the ingress rules.

We start by downloading a NodePort service template that we’ll modify to act as a LoadBalancer:

$ curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/service-nodeport.yaml -o svc-ingress-nginx-lb.yaml

Here, we download a NodePort service template (service-nodeport.yaml) from the NGINX ingress GitHub repository and save it as svc-ingress-nginx-lb.yaml on our local machine.

Now, let’s modify this file to set up our LoadBalancer. To do this, we’ll edit the downloaded file to change the service type to LoadBalancer and add the externalIPs field with the IP addresses of our nodes. The modified spec section of the file should now look something like:

spec:
  type: LoadBalancer
  externalIPs:
    - 192.168.121.110
    - 192.168.121.111
    - 192.168.121.112
  externalTrafficPolicy: Local

Here, externalIPs specifies the external IP addresses assigned to the nodes in the cluster. Traffic to these IPs will be routed to the ingress controller. Also, externalTrafficPolicy: Local ensures that traffic is only routed to local pods on the node receiving the request, reducing unnecessary network hops and preserving the source IP address.

2.3. Applying the Configuration

After saving the file, we need to apply the configuration to our cluster with kubectl:

$ kubectl apply -f svc-ingress-nginx-lb.yaml
service/ingress-nginx-lb created

This will create a LoadBalancer service that routes external traffic to the NGINX ingress controller.

Finally, we can now verify the creation of the LoadBalancer service with the correct external IPs:

$ kubectl get svc -n ingress-nginx
NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP            PORT(S)                      AGE
ingress-nginx-lb       LoadBalancer   10.96.105.34   192.168.121.110,...   80:31213/TCP,443:31813/TCP   1m

Our output shows the creation of ingress-nginx-lb service as a LoadBalancer type, with the EXTERNAL-IP field listing the IPs we configured. These IPs are now accessible externally, allowing traffic to reach the NGINX ingress controller, which will then distribute it according to the ingress rules.

3. Configuring Ingress Resources

With the ingress controller up and running, our next step is to configure ingress resources. These resources define the route of external requests to appropriate services within our cluster. This configuration allows us to consolidate multiple services under a single IP address or hostname, making our services more accessible and easier to manage.

3.1. Setting up Sample Applications

To demonstrate how ingress works and retrieve the IP address later, we’ll set up two simple applications: an NGINX web server and an EchoServer. EchoServer is a simple server that responds with the details of the request it receives, making it useful for testing. We’ll create Deployments for both applications and then expose them as Services.

Let’s start by creating our Deployments.

First, let’s deploy the nginx web server:

$ kubectl create deployment nginx --image=nginx --port=80
deployment.apps/nginx created

Here, we create a new Deployment nginx using the official NGINX image from Docker Hub. The –port=80 flag specifies that the container will listen on port 80.

Next, let’s deploy the EchoServer:

$ kubectl create deployment echoserver --image=gcr.io/google_containers/echoserver:1.4 --port=8080
deployment.apps/echoserver created

Similarly, we create a Deployment echoserver using the EchoServer image from Google’s container registry. The server listens on port 8080, which is specified by the –port=8080 flag.

Now, we need to expose these Deployments as Services to be accessible within the cluster with kubectl expose.

For the nginx service, let’s run:

$ kubectl expose deployment nginx --port=80 --type=NodePort
service/nginx exposed

The service will now route traffic to port 80 of the nginx pod.

Similarly, let’s expose the EchoServer Deployment as a Service:

$ kubectl expose deployment echoserver --port=8080 --type=NodePort
service/echoserver exposed

Finally, let’s verify the creation of both Services and that they are running correctly:

$ kubectl get services
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
echoserver   NodePort    10.100.200.45    <none>        8080:31250/TCP   30s
nginx        NodePort    10.100.200.75    <none>        80:32018/TCP     45s

With our sample applications now running and exposed as services, we’re ready to set up ingress to route external traffic to these services and retrieve the ingress endpoint or IP address.

3.2. Creating an Ingress Resource

Now that our applications and the NGINX ingress controller are up and running, we can create an ingress resource to define the route of external traffic to our services.

We start by creating a YAML configuration for the ingress resource. This configuration will specify that requests to /nginx should be routed to the nginx service, and requests to /echo should be routed to the echoserver service.

Let’s see the YAML configuration:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fanout-nginx-ingress
  namespace: default
spec:
  rules:
  - http:
      paths:
      - path: /nginx
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80
      - path: /echo
        pathType: Prefix
        backend:
          service:
            name: echoserver
            port:
              number: 8080

Our YAML defines an ingress resource fanout-nginx-ingress in the default namespace. It specifies two paths /nginx and /echo and associates them with the respective services. The pathType is set to Prefix, meaning any request that starts with the specified path will be routed to the corresponding backend service.

Let’s now apply the ingress configuration file to our cluster:

$ kubectl apply -f ingress.yaml
ingress.networking.k8s.io/fanout-nginx-ingress created

To ensure we have the correct configuration for our ingress resource, let’s check it with kubectl describe:

$ kubectl describe ing fanout-nginx-ingress
Name: fanout-nginx-ingress
Namespace: default
Address: 192.168.121.110
Rules:
Host Path Backends
---- ---- --------
* /nginx nginx:80 (10.244.1.5:80)
/echo echoserver:8080 (10.244.1.6:8080)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 1m nginx-ingress-controller Scheduled for sync

With this setup, the ingress resource now directs traffic based on the specified paths to the appropriate services within the cluster. Requests to /nginx are routed to the nginx service, and requests to /echo are routed to the EchoServer service.

This configuration will also allow us to retrieve the ingress endpoint or IP address later to access these services externally.

4. Retrieving the Ingress Endpoint or IP Address

After configuring our ingress resource, we can now retrieve the ingress endpoint or IP address. This is the external address that clients will use to access the services defined in our ingress resource.

4.1. Using kubectl to Get the Ingress Address

The simplest way to retrieve the ingress IP address is by using the kubectl command:

$ kubectl get ing
NAME                    CLASS    HOSTS   ADDRESS          PORTS   AGE
fanout-nginx-ingress    <none>   *       192.168.121.110  80      5m 

As we can see, an IP address in the ADDRESS column is the external IP address assigned to the ingress. Clients will use this IP address to access the services. In our example above, the IP is 192.168.121.110. We now have the endpoint that external clients can use to access the nginx and EchoServer services via the defined paths.

4.2. Verifying Access to Services via Ingress

After obtaining the ingress IP address, we should verify that the services are accessible through the ingress. We can do this by sending HTTP requests to the ingress paths using tools like curl or by accessing them via a web browser.

For example, let’s use curl to test if the NGINX service is accessible via the ingress:

$ curl http://192.168.121.110/nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; }
...
</body>
</html>

Our output confirms that the nginx service is successfully accessible via the ingress at the /nginx path. The response is the default NGINX welcome page.

Similarly, we can also test if the EchoServer service is accessible:

$ curl http://192.168.121.110/echo
{
  "host": "echoserver-6df5b57bdc-b2msl",
  "uri": "/echo",
  "headers": {
    "host": "192.168.121.110",
    "user-agent": "curl/7.68.0",
    "accept": "*/*"
  }
}

Our output is a JSON response generated by the EchoServer. It includes details about the request, such as the request URI (/echo), headers, and the pod that processed the request (host). This confirms that the EchoServer service is also accessible via the ingress at the /echo path.

5. Conclusion

In this article, we’ve explored the process of obtaining a Kubernetes ingress endpoint/IP address. Ingress offers powerful tools for managing incoming traffic in our clusters. We started with the basics of Kubernetes ingress and set up sample applications, including the installation of an ingress controller. We then created an ingress resource and discussed how to retrieve its endpoint.

We’ve seen how ingress plays a crucial role in Kubernetes networking, providing a flexible way to route external traffic to our services.