Kubernetes NodePort type endpoints & ports

8/16/2018

Following the interactive tutorial on kubernetes.io where a NodePort type service is created via kubectl expose deploy kubernetes-bootcamp --type="NodePort" --port 8080 I am confused about the results.

First the tutorial states

Let's run (...) kubectl get services (...) we see that the service received (...) an external-IP (the IP of the Node).

This is not true according to the output, no external IP:

NAME                TYPE        CLUSTER-IP      EXTERNAL-IP PORTS
kubernetes-bootcamp NodePort    ...             <none>      8080:31479

Now with kubectl describe service kubernetes-bootcamp one gets:

Type        NodePort
IP          ...
Port        <unset> 8080/TCP
NodePort    <unset> 31479/TCP

Now the tutorial suggests to curl $(minikube ip):$NODE_PORT which equals curl <internal node IP>:<NodePort> - which works, but leaves many questions:

  • According to kubectl expose -h the --port command specifies the port on which to serve, thus I expected --port to set the exposed <NodePort> for NodePort type services, but that is not the case. Why and how to set it?
  • The <internal node IP> under which the container app can indeed be reached is not shown anywhere in the service metadata, I can only get it from kubectl get nodes. Why?
  • The IP shown through kubectl describe service (which equals the cluster IP) combined with the port also shown there (which equals the one set via --port) also routes to the container app, thus curl <clusterIP>:8080 works and fulfills the promise that you can set the exposed port via --port. But in an unexpected way: why does a NodePort service have such a clusterIP type interface?
  • What is the meaning of the Endpoints shown through kubectl describe service if it is neither the clusterIP endpoint nor the NodePort endpoint?
-- B M
docker
kubernetes

1 Answer

8/16/2018

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.

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

You also see ClusterIP because that is the way to get to the service within 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.

What is the meaning of the Endpoints shown through kubectl describe service if it is neither the clusterIP endpoint nor the NodePort endpoint?

The endpoints value of 172.18.0.2:8080 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).

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

This links to the point that the output you see from kubectl get services and kubectl describe service <service> when exposing via NodePort is a bit misleading - one would expect to see something in or analogous to external-ip 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 external-ip 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.

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

The expose command-line option is especially limited as you currently can't even use it to choose which port in the NodePort range is used. 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.

-- Ryan Dawson
Source: StackOverflow