<p>Following the interactive tutorial on <a href="https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/" rel="nofollow noreferrer">kubernetes.io</a> where a <code>NodePort</code> type service is created via <code>kubectl expose deploy kubernetes-bootcamp --type=&quot;NodePort&quot; --port 8080</code> I am confused about the results.</p>
<p>First the tutorial states</p>
<blockquote>
<p>Let's run (...) <code>kubectl get services</code> (...) we see that the service received (...) an external-IP (the IP of the Node).</p>
</blockquote>
<p>This is not true according to the output, no external IP:</p>
<pre><code>NAME                TYPE        CLUSTER-IP      EXTERNAL-IP PORTS
kubernetes-bootcamp NodePort    ...             &lt;none&gt;      8080:31479
</code></pre>
<p>Now with <code>kubectl describe service kubernetes-bootcamp</code> one gets:</p>
<pre><code>Type        NodePort
IP          ...
Port        &lt;unset&gt; 8080/TCP
NodePort    &lt;unset&gt; 31479/TCP
</code></pre>
<p>Now the tutorial suggests to <code>curl $(minikube ip):$NODE_PORT</code> which equals <code>curl &lt;internal node IP&gt;:&lt;NodePort&gt;</code> - which works, but leaves many questions:</p>
<ul>
<li>According to <code>kubectl expose -h</code> the <code>--port</code> command specifies the port on which to serve, thus I expected <code>--port</code> to set the exposed <code>&lt;NodePort&gt;</code> for <code>NodePort</code> type services, but that is not the case. Why and how to set it?</li>
<li>The <code>&lt;internal node IP&gt;</code> under which the container app can indeed be reached is not shown anywhere in the service metadata, I can only get it from <code>kubectl get nodes</code>. Why?</li>
<li>The <code>IP</code> shown through <code>kubectl describe service</code> (which equals the cluster IP) combined with the port also shown there (which equals the one set via <code>--port</code>) also routes to the container app, thus <code>curl &lt;clusterIP&gt;:8080</code> works and fulfills the promise that you can set the exposed port via <code>--port</code>. But in an unexpected way: why does a <code>NodePort</code> service have such a <code>clusterIP</code> type interface?</li>
<li>What is the meaning of the <code>Endpoints</code> shown through <code>kubectl describe service</code> if it is neither the <code>clusterIP</code> endpoint nor the <code>NodePort</code> endpoint?</li>
</ul>

<p>It will help to break this down but the general theme is that NodePort isn't the most common way to expose services outside of a cluster so some of the features around it aren't all that intuitive. LoadBalancer (or an ingress controller using it) is the preferred way to expose services to the world outside the cluster.</p>

<blockquote>
  <p>The IP shown through <code>kubectl describe service</code> (which equals the cluster IP) combined with the port also shown there (which equals the one set via <code>--port</code>) also routes to the container app, thus <code>curl &lt;clusterIP&gt;:8080</code> works and fulfills the promise that you can set the exposed port via <code>--port</code>. But in an unexpected way: why does a NodePort service have such a clusterIP type interface?</p>
</blockquote>

<p>You also see ClusterIP because that is the way to get to the service <em>within</em> the cluster. Other services can reach that service within the cluster using that service name and port (8080 in this case) but ClusterIP in itself doesn't make the service available outside of the cluster. </p>

<blockquote>
  <p>What is the meaning of the Endpoints shown through <code>kubectl describe service</code> if it is neither the clusterIP endpoint nor the NodePort endpoint?</p>
</blockquote>

<p>The endpoints value of <code>172.18.0.2:8080</code> or similar will be the internal IP and port for the service. Within the cluster you can also reach the service via its name using the cluster's internal dns (which is normally the more convenient way).</p>

<blockquote>
  <p>The <code>&lt;internal node IP&gt;</code> under which the container app can indeed be reached is not shown anywhere in the service metadata, I can only get it from <code>kubectl get nodes</code>. Why?</p>
</blockquote>

<p>This links to the point that the output you see from <code>kubectl get services</code> and <code>kubectl describe service &lt;service&gt;</code> when exposing via NodePort is a bit misleading - one would expect to see something in or analogous to <code>external-ip</code> for the entry. NodePort dedicates a port on that node just for that service. This is a bit limiting as if you kept doing that for each service you add then you'll run out of ports. So the <code>external-ip</code> if one were to be shown would have to be the IP of the node, which might look a bit odd when shown alongside the IPs of LoadBalancer-type services.</p>

<blockquote>
  <p>According to <code>kubectl expose -h</code> the <code>--port</code> command specifies the port on which to serve, thus I expected <code>--port</code> to set the exposed <code>NodePort</code> for NodePort type services, but that is not the case. Why and how to set it?</p>
</blockquote>

<p>The expose command-line option is especially limited as you currently <a href="https://github.com/kubernetes/kubernetes/issues/25478" rel="nofollow noreferrer">can't even use it to choose which port in the NodePort range is used</a>. In your case you've been given the external port 31479 but you didn't get to choose that. It might not be advisable to let users choose that too easily as there are a limited number of ports available and you could easily find yourself allocating the same port twice. But you can choose it the external port when deploying via descriptor files.</p>
