Exposing a running application externally is a primary task in Kubernetes networking. This involves two common methods: using a NodePort Service for direct access, and configuring an Ingress resource for more flexible, host-based routing.
Before you begin, ensure you have a local Kubernetes cluster running, such as Minikube, and kubectl configured to interact with it.
First, let's deploy a simple web application that we can use for our experiments. This application is a simple Nginx server that will respond to HTTP requests. Save the following manifest as webapp-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-deployment
spec:
replicas: 2
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: nginx-container
image: nginx:1.21
ports:
- containerPort: 80
Apply this manifest to your cluster to create the Deployment and its associated Pods:
kubectl apply -f webapp-deployment.yaml
Verify that the Pods are running:
kubectl get pods -l app=webapp
You should see two Pods with a status of Running. These Pods have IP addresses, but they are only reachable from within the cluster. Our goal is to make them accessible from outside.
Our first step is to create a Service that provides a stable endpoint for our webapp Pods. We will use the NodePort type, which exposes the Service on a specific port on each of the cluster's nodes. This is a straightforward way to get external traffic to your application, especially in development environments.
Save the following manifest as webapp-nodeport-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: webapp-service
spec:
type: NodePort
selector:
app: webapp
ports:
- protocol: TCP
port: 80 # Port on which the service is available inside the cluster
targetPort: 80 # Port on the Pods that the service forwards traffic to
# nodePort: 30080 # Optionally, you can specify a port. If omitted, Kubernetes picks one.
Here's a breakdown of the manifest:
spec.type: NodePort: This specifies the type of Service.spec.selector.app: webapp: This is the important link. The Service will route traffic to any Pod that has the label app: webapp.spec.ports: This section defines the port mapping. Traffic hitting the Service on port: 80 will be forwarded to targetPort: 80 on the selected Pods. Kubernetes will also allocate a high-numbered port on the node (the nodePort) that forwards to the Service's port 80.Apply the Service manifest:
kubectl apply -f webapp-nodeport-service.yaml
Now, inspect the created Service:
kubectl get service webapp-service
The output will look something like this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
webapp-service NodePort 10.108.146.13 <none> 80:31501/TCP 25s
Notice the PORT(S) column. It shows that port 80 on the Service's internal CLUSTER-IP is mapped to a nodePort, in this case, 31501. Your port number will likely be different. Traffic sent to any node in your cluster on port 31501 will be routed to our webapp Pods on port 80.
Traffic flow for a NodePort Service. An external request hits a worker node's IP address on the designated NodePort, which Kubernetes then routes through the Service to one of the target Pods.
To access it, you can use the minikube service command, which is a convenient shortcut:
minikube service webapp-service --url
This command will open the application in your browser or print a URL, like http://192.168.49.2:31501. Visiting this URL will show you the default Nginx welcome page, served from one of your Pods.
NodePort is effective but has limitations. You generally don't want to expose arbitrary high-numbered ports to users. Ingress provides a more sophisticated way to manage external access, offering HTTP and HTTPS routing, host-based routing, and path-based routing.
To use Ingress, you need an Ingress controller running in your cluster. For Minikube, you can enable the built-in Nginx Ingress controller with a simple command:
minikube addons enable ingress
After enabling the addon, wait a minute for the controller Pods to start. You can check their status in the ingress-nginx namespace: kubectl get pods -n ingress-nginx.
Now, let's create an Ingress resource. This resource will define a rule: any traffic for the host webapp.example.com should be sent to our webapp-service. Note that for Ingress to work, the Service it points to does not need to be a NodePort. It can be the default ClusterIP type, as the Ingress controller runs inside the cluster and can reach internal Service IPs. We can continue using our webapp-service.
Save the following manifest as webapp-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
spec:
rules:
- host: "webapp.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-service
port:
number: 80
Apply the Ingress manifest:
kubectl apply -f webapp-ingress.yaml
Check the status of the Ingress:
kubectl get ingress webapp-ingress
It may take a moment for an address to be assigned. Once ready, the output will show the address of the Ingress controller.
NAME CLASS HOSTS ADDRESS PORTS AGE
webapp-ingress nginx webapp.example.com 192.168.49.2 80 50s
The final step is to make your local machine resolve webapp.example.com to the cluster's IP address. We can do this by editing your local hosts file.
Find your Minikube IP: Run minikube ip.
Edit your hosts file:
sudo nano /etc/hostsC:\Windows\System32\drivers\etc\hosts as an Administrator.Add an entry: Add a new line that maps the Minikube IP to your chosen hostname. For example, if your Minikube IP is 192.168.49.2:
192.168.49.2 webapp.example.com
Save the file. Now, your computer knows where to send requests for webapp.example.com.
Traffic flow for an Ingress. An external request arrives at the Ingress controller. The controller inspects the request's hostname, consults the Ingress resource for routing rules, and forwards the request to the appropriate backend Service.
You can now access your application using curl or a web browser with the hostname:
curl http://webapp.example.com
You should see the same Nginx welcome page. You have successfully exposed your application using host-based routing, a more flexible and production-ready pattern.
To keep your cluster tidy, it's good practice to remove the resources you created during this practical session. You can delete them by referencing the manifest files you used to create them.
kubectl delete -f webapp-ingress.yaml
kubectl delete -f webapp-nodeport-service.yaml
kubectl delete -f webapp-deployment.yaml
Also, remember to remove the entry you added to your /etc/hosts file.
Was this section helpful?
NodePort, ClusterIP, and LoadBalancer types. It explains how services enable network access to a set of Pods.© 2026 ApX Machine LearningEngineered with