Minikube can make your ClusterIP services accessible on your local machine, even though ClusterIP is designed for internal cluster communication.

Let’s say you have a simple Nginx deployment and service running in Minikube:

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:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

If you apply this to your Minikube cluster (kubectl apply -f your-manifest.yaml), you’ll see the service is created with type ClusterIP:

$ kubectl get service nginx-service
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx-service   ClusterIP   10.100.100.100   <none>        80/TCP    1m

By default, 10.100.100.100 is only reachable from within the Minikube VM. You can verify this by trying to curl 10.100.100.100 from your host machine – it won’t work.

Minikube provides a command specifically for this: minikube service. When used with a service name and the --url flag, it gives you a URL that maps to your service.

$ minikube service nginx-service --url
http://127.0.0.1:56789/

This output http://127.0.0.1:56789/ is a local proxy. Minikube sets up a port-forwarding mechanism on your host machine that directs traffic sent to 127.0.0.1:56789 into the Minikube cluster, specifically to your nginx-service on port 80.

Now, if you curl this local URL:

$ curl http://127.0.0.1:56789/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

You get the default Nginx welcome page, proving you can access your ClusterIP service from your host.

The minikube service command essentially automates the creation of a Kubernetes PortForward resource and runs kubectl port-forward for you. It finds an available port on your local machine and sets up the tunnel.

The core problem minikube service solves is bridging the network gap between your host machine and the isolated network of the Kubernetes cluster running inside the Minikube VM. ClusterIP services are assigned an IP address within the cluster’s internal network (e.g., 10.100.100.100), which is not directly routable from your host. minikube service creates a dynamic tunnel, exposing a port on localhost that forwards traffic to that internal ClusterIP and port.

You can also use minikube service to open the service in your browser directly:

$ minikube service nginx-service

This command will output the URL and then automatically open it in your default web browser.

The underlying mechanism is kubectl port-forward. If you wanted to do it manually, you’d first find the service’s ClusterIP:

CLUSTER_IP=$(kubectl get service nginx-service -o jsonpath='{.spec.clusterIP}')

Then, you’d find an available local port (e.g., 8080) and run:

kubectl port-forward service/nginx-service 8080:80

Or, to forward directly to the ClusterIP (less common for services, more for pods):

kubectl port-forward "clusterip/$CLUSTER_IP" 8080:80 --address 127.0.0.1

This manual approach is what minikube service abstracts away. It handles finding a free local port and ensuring the tunnel is correctly established.

One subtle point is that minikube service is primarily for ClusterIP and NodePort services. For LoadBalancer services, Minikube typically uses minikube tunnel to simulate a cloud load balancer, which is a different mechanism. However, minikube service will still work for NodePort services by exposing the NodePort on localhost.

The next step after exposing a service is often dealing with persistent data. If your application requires storage, you’ll need to explore Minikube’s persistent volume capabilities and how they map to your host filesystem.

Want structured learning?

Take the full Minikube course →