<p>I've set up a <strong>minikube</strong> cluster on an Azure's Ubuntu instance that exposes an external service on the IP: <code>192.168.49.2:30000</code></p>
<p><code>curl 192.168.49.2:30000</code> returns the desired output.
How can I access this service using a browser on my local machine using the azure host public IP address ?</p>

<h3>Explanation:</h3>
<hr />
<h3>EDIT:</h3>
<p>OK, I see that <strong>docker</strong> driver by default uses <code>192.168.49.2</code> IP address:</p>
<pre><code>azureuser@minikube:~$ minikube service web --url
http://192.168.49.2:31527
</code></pre>
<p>so most probably you've used this one. Although the further explanation is based on <strong>virtualbox</strong> example it can be fully applied also in this case, with the only difference that <strong>minikube</strong> runs as an isolated docker container and not as a VM. But if you run <code>docker ps</code> on your <strong>Azure VM instance</strong> you'll see only one container, named <code>minikube</code>:</p>
<pre><code>azureuser@minikube:~$ docker ps
CONTAINER ID        IMAGE                                 COMMAND                  CREATED             STATUS              PORTS                                                                                                      NAMES
af68ab219c6c        gcr.io/k8s-minikube/kicbase:v0.0.14   &quot;/usr/local/bin/entr…&quot;   53 minutes ago      Up 53 minutes       127.0.0.1:32771-&gt;22/tcp, 127.0.0.1:32770-&gt;2376/tcp, 127.0.0.1:32769-&gt;5000/tcp, 127.0.0.1:32768-&gt;8443/tcp   minikube
</code></pre>
<p>Only after running:</p>
<pre><code>azureuser@minikube:~$ minikube ssh
</code></pre>
<p>and then:</p>
<pre><code>docker@minikube:~$ docker ps
</code></pre>
<p>you'll see both the container running by your <strong>app <code>Pod</code></strong> as well as <strong>kubernetes control plane components</strong>. The list is quite long so I won't put it here.</p>
<p>But it shows that your <strong>kubernetes</strong> cluster is in practice isolated in a very similar way from your <strong>Azure VM</strong> host as in case when it runs in a <strong>nested VM</strong>. The key point here is that minikube cluster's network is isolated from host VM network and <code>NodePort</code> Service is accessible only on the external IP of a VM or <code>minikube</code> docker container, not exposing any port on any of host VM network interfaces.</p>
<hr />
<p>I've reproduced your case, assuming that you started your minikube with <a href="http://%20https://minikube.sigs.k8s.io/docs/drivers/virtualbox/" rel="noreferrer">virtualbox driver</a>, so please correct me if my assumption was wrong. You could've started it this way:</p>
<pre><code>minikube start --driver=virtualbox
</code></pre>
<p>or simply:</p>
<pre><code>minikube start
</code></pre>
<p>If you've installed <strong>VirtualBox</strong> on your <strong>minikube</strong> vm, it will be also automatically detected and <code>virtualbox</code> driver will be used.</p>
<p>OK, so let's pause for a moment at this point and take a closer look what such approach implies.</p>
<p>Your <strong>minikube</strong> runs inside your <strong>Azure VM</strong> but it doesn't run directly on it. Nested virtualization is used and your minikube kubernetes cluster actually runs on a vm inside another vm.</p>
<p>So if you've exposed your <code>Deployment</code> using <code>NodePort</code> service, it makes it available on the external IP address of <strong>minikube vm</strong> (which is nested vm). But this IP is external only from the perspective of this vm.</p>
<p>Let's ssh into our <strong>Azure VM</strong> and run:</p>
<pre><code>azureuser@minikube:~$ minikube service web --url
http://192.168.99.100:31955
</code></pre>
<p>Your service name and address will be different but I'm showing it just to illustrate the idea.</p>
<p>Then run:</p>
<pre><code>azureuser@minikube:~$ ip -4 a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc mq state UP group default qlen 1000
    inet 10.0.0.4/24 brd 10.0.0.255 scope global eth0
       valid_lft forever preferred_lft forever
3: vboxnet0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet 192.168.99.1/24 brd 192.168.99.255 scope global vboxnet0
       valid_lft forever preferred_lft forever
</code></pre>
<p>As you can see <code>192.168.99.100</code> is reachable via <code>vboxnet0</code> network interface as it's part of <code>192.168.99.0/24</code> network, used by virtualbox vm.</p>
<p>Therefore there are no means for it to be reachable without using additional port forwarding, not only on the external IP of the <strong>Azure VM</strong> but on any of its internal network interfaces. <code>NodePort</code> service exposes the <code>Deployment</code> only on the external IP of the nested <strong>VirtualBox VM</strong> (or other hypervisor), which is reachable from <strong>Azure VM</strong> host but it's not exposed on any of it's network interfaces so it cannot be reached from outside either.</p>
<h3>Solution:</h3>
<p>Did I just say port forwarding ? Fortunately <code>kubectl</code> makes it fairly easy task. If you haven't installed it so far on your <strong>Azure VM</strong>, please do it as <code>minikube kubectl</code> may not work. You can use for it the following command:</p>
<pre><code>kubectl port-forward --address 0.0.0.0 service/&lt;service-name&gt; 8080:8080
</code></pre>
<p>which will forward the traffic destined to any of <strong>Azure VM</strong> addresses (also the public one) to your <code>Service</code>, which in this case doesn't even have to be of <code>NodePort</code> type, <code>ClusterIP</code> will also work.</p>
<p>Caveat: To be able to bind to a well known port such as <code>80</code> you need to run this command as <code>root</code>. If you use registered ports, starting from <code>1024</code> such as <code>8080</code> you don't need root access. So after running:</p>
<pre><code>root@minikube:~# kubectl port-forward --address 0.0.0.0 service/web 80:8080
</code></pre>
<p>You should be able to access your app without any problems by using the external IP address of your <strong>Azure VM</strong>.</p>
