NodePort Service resources are used to expose your pods to the external world. Creating a NodePort Service resource spins up a ClusterIP Service resource and maps the ClusterIP port to a random high port number (default: 30000-32767) on all cluster nodes. You can also specify
a static NodePort number if you so desire. So, with a NodePort Service resource, you can access your pods using the IP address of any node within your cluster and the NodePort of the service.
Tip
Though it is possible to specify a static NodePort number, you should avoid using it. That is because you might end up in port conflicts with otherService resources and put a high dependency on config and change management. Instead, keep things simple and use dynamic ports.
Going by the Flask application example, let’s create a flask-app pod with the redis Service resource we created before, acting as its backend, and then we will expose the pod on NodePort.
Use the following command to create a pod imperatively:
$ kubectl run flask-app –image=<your_dockerhub_user>/python-flask-redis
Now, as we’ve created the flask-app pod, let’s check its status using the following command:
$ kubectl get pod flask-app
NAME
READY
STATUS
RESTARTS
AGE
flask-app
1/1
Running
0
19s
The flask-app pod is running successfully and is ready to accept requests. It’s time to understand the resource manifest for the NodePort Service resource, flask-nodeport.yaml:
…
spec:
ports:
port: 5000
protocol: TCP
targetPort: 5000
selector:
run: flask-app
type: NodePort
The manifest is similar to the ClusterIP manifest but contains a type attribute specifying the Service resource type—NodePort.
Let’s apply this manifest to see what we get using the following command:
$ kubectl apply -f flask-nodeport.yaml
Now, let’s list the Service resource to get the NodePort Service using the following command:
$ kubectl get service flask-app
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
flask-app NodePort 10.3.240.246 <none> 5000:32618/TCP 9s
And we see that the type is now NodePort, and the container port 5000 is mapped to node port 32618.
If you are logged in to any Kubernetes node, you can access the Service resource using localhost:32618. But as we are using Google Cloud Shell, we need to SSH into a node to access the Service resource.
Let’s list the nodes first using the following command:
$ kubectl get nodes | ||||
NAME | STATUS | ROLES | AGE | VERSION |
gke-node-1dhh Ready | <none> | 17m | v1.26.15-gke.4901 | |
gke-node-7lhl Ready | <none> | 17m | v1.26.15-gke.4901 | |
gke-node-zwg1 | Ready | <none> | 17m | v1.26.15-gke.4901 |
And as we can see, we have three nodes. Let’s SSH into the gke-node-1dhh node using the following command:
$ gcloud compute ssh gke-node-1dhh
Now, as we are within the gke-node-1dhh node, let’s curl localhost:32618 using the following command:
$ curl localhost:32618
Hi there! This page was last visited on 2023-06-26, 08:37:50.
And we get a response back! You can SSH into any node and curl the endpoint and should get a similar response.
To exit from the node and get back to the Cloud Shell prompt, run the following command:
$ exit
Connection to 35.202.82.74 closed.
And you are back at the Cloud Shell prompt.
Tip
A NodePort Service resource is an intermediate kind of resource. This means that while it forms an essential building block of providing external services, it is not used on its own most of the time. When you are running on the cloud, you can use LoadBalancer Service resources instead. Even for an on-premises setup, it makes sense not to use NodePort for every Service resource and instead use Ingress resources.
Now, let’s look at the LoadBalancer Service resource used extensively to expose your Kubernetes workloads externally.