AB
Learn how to expose Kubernetes services in Minikube using Ingress controllers, with step-by-step instructions and troubleshooting tips for local development environments.
While working with Kubernetes on Minikube, one of the major roadblocks developers face is exposing services externally without relying on a cloud LoadBalancer. This guide walks you through how to use an Ingress controller in Minikube to route traffic to your services, replacing the need for a cloud LoadBalancer — with all the troubleshooting included.
To expose a Kubernetes nginx
service running in Minikube using an Ingress controller, making it accessible via a custom domain (nginx.local
) without using a cloud provider LoadBalancer.
Before diving in, ensure you have the following tools installed and configured:
Important: Before starting Minikube, ensure Docker is running on your system. Minikube uses Docker as its default driver to pull container images and manage the Kubernetes node.
Run the following command to start your Minikube cluster:
minikube start
This initializes a single-node Kubernetes cluster using the Docker driver. Verify Docker is running beforehand, as Minikube will fail to start without it.
Note: Depending on your computer’s specifications, Minikube may take several minutes to start, especially on the first run when it needs to download images. Be patient and don’t interrupt the process. If you’re on a system with limited resources, this could take even longer.
After Minikube starts, verify that the necessary Docker images have been downloaded:
docker images | grep minikube
You should see several images related to Minikube. Also, check that the Minikube containers are running:
docker ps | grep minikube
You should see at least one container running for Minikube.
We’ll deploy a simple NGINX web server and expose it via a Kubernetes service.
Save the following as nginx-deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nginx-deployment.yaml
This YAML file defines two Kubernetes resources: a Deployment and a Service. Let’s break it down:
Deployment Section:
apiVersion: apps/v1
: Specifies the Kubernetes API version for deployments.kind: Deployment
: Indicates we’re creating a Deployment resource to manage a set of pods.metadata
: Provides metadata like the deployment’s name (nginx-deployment
).spec
:replicas: 1
: Ensures one pod is running.selector
: Links the deployment to pods with the label app: nginx
.template
: Defines the pod configuration.metadata
: Assigns the label app: nginx
to the pod.spec
:containers
: Defines the container(s) in the pod.name: nginx
: Names the container.image: nginx
: Uses the official NGINX image from Docker Hub.ports
: Exposes port 80 on the container for HTTP traffic.Service Section:
apiVersion: v1
: Uses the core Kubernetes API for services.kind: Service
: Creates a Service to expose the deployment.metadata
: Names the service nginx-service
.spec
:selector
: Routes traffic to pods with the label app: nginx
.ports
:port: 80
: The service listens on port 80.targetPort: 80
: Forwards traffic to port 80 on the pods.Apply the configuration:
kubectl apply -f nginx-deployment.yaml
This creates the NGINX deployment and service in your Minikube cluster.
To verify the service is running, run:
kubectl get svc nginx-service
and then to verify the pods are running, run:
kubectl get pods -l app=nginx
Run the following command to enable the Ingress addon:
minikube addons enable ingress
The Ingress addon in Minikube deploys an NGINX Ingress Controller, a Kubernetes resource that manages external HTTP/HTTPS traffic. Here’s a detailed explanation:
ingress-nginx
namespace, along with necessary configurations like services and ConfigMaps.LoadBalancer
service, which Minikube simulates locally using its networking setup.Verify the controller is running:
kubectl get pods -n ingress-nginx
Look for a pod named ingress-nginx-controller-...
in the Running
state. This confirms the controller is ready to handle Ingress rules.
Save the following as nginx-ingress.yaml
:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: nginx.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
nginx-ingress.yaml
This YAML defines an Ingress resource to route traffic to the nginx-service
. Here’s a detailed breakdown:
apiVersion: networking.k8s.io/v1
: Uses the networking API for Ingress resources.kind: Ingress
: Specifies an Ingress resource.metadata
: Names the Ingress nginx-ingress
.annotations
:nginx.ingress.kubernetes.io/rewrite-target: /
: Rewrites the URL path to /
before forwarding to the service. This ensures requests to nginx.local/*
are routed correctly.spec
:rules
: Defines routing rules.host: nginx.local
: Routes requests for the nginx.local
domain.http
:paths
:path: /
: Matches all requests to the root path.pathType: Prefix
: Allows matching of paths starting with /
.backend
: Specifies the target service.service
:name: nginx-service
: Forwards traffic to the nginx-service
.port
:number: 80
: Targets port 80 on the service.Apply the configuration:
kubectl apply -f nginx-ingress.yaml
This creates the Ingress resource, which the NGINX Ingress Controller uses to route traffic.
To verify the Ingress resource is created, run:
kubectl get ingress nginx-ingress
/etc/hosts
FileTo resolve nginx.local
locally, add an entry to your /etc/hosts
file:
127.0.0.1 nginx.local
Note: Use
127.0.0.1
(localhost) instead of Minikube’s IP, as theminikube tunnel
(covered next) binds the Ingress controller to your local machine’s network interface. On Windows, editC:\Windows\System32\drivers\etc\hosts
as Administrator. On macOS/Linux, usesudo nano /etc/hosts
.
Run the following in a separate terminal:
minikube tunnel
Note: Keep this terminal open! The tunnel exposes the Ingress controller’s
LoadBalancer
service to your local network, allowing traffic to reachnginx.local
.
With the tunnel running, test the setup:
curl http://nginx.local
You should see the default NGINX welcome page HTML. Alternatively, open http://nginx.local
in your browser to view the page.
Setting up Ingress on Minikube can be tricky. Here are issues we encountered and their fixes:
Issue: Running kubectl get pods -n ingress-nginx
showed:
No resources found in ingress-nginx namespace
Fix: The Ingress addon hadn’t finished deploying. Wait a few moments and recheck. If it persists, re-run minikube addons enable ingress
.
Issue: Curl returned:
curl: (6) Could not resolve host: nginx.local
Fix: Ensure 127.0.0.1 nginx.local
is added to /etc/hosts
.
Issue: Curl failed with:
curl: (28) Failed to connect to nginx.local port 80
Fix: Start the minikube tunnel
to expose the LoadBalancer
service.
To explicitly set the Ingress controller’s service to LoadBalancer
,run:
kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{"spec": {"type": "LoadBalancer"}}'
This was optional, as Minikube’s tunnel handles this, but it helped confirm the service configuration.
By following this guide, you’ve:
nginx.local
./etc/hosts
for local DNS resolution.minikube tunnel
to expose the service.When you’re done experimenting, it’s important to properly clean up your resources to free up system resources. Follow these steps:
If you have the minikube tunnel
running in a terminal, press Ctrl+C
to stop it.
Remove the Ingress, Service, and Deployment:
kubectl delete ingress nginx-ingress
kubectl delete service nginx-service
kubectl delete deployment nginx-deployment
Stop the Minikube cluster:
minikube stop
This will shut down the Minikube VM but preserve your cluster state.
If you want to completely remove the Minikube cluster:
minikube delete
This will delete all cluster data and the Minikube VM.
Using Ingress in Minikube simulates cloud-like service exposure in a local environment. While it requires manual steps like editing /etc/hosts
and running a tunnel, it offers a cost-free way to learn Kubernetes networking and gain hands-on experience with Ingress controllers.