I recently started building Kubernetes cluster in my on-prem network where I do not have OpenStack or OpenShift that can provide me load balancer IP. Most cloud platforms have load balancer logic already written that can provision IP address upon service is created with type LoadBalancer. In my senario, I will expose my application service via type NodePort that will expose port on all the worker nodes and redirect traffic to right pod.

NOTE: You will need to manually enter NODE_IP:EXPOSE_PORT in your on-prem load balancer. If you have an automation that can do for you thats great!

To expose your pod to outside Kubernetes cluster, you need to create a yaml file and then deploy it on your master node. There are other ways to expose pod service via command line as well. I will go over in the end of this section.

I will first create a pod and then I will go over services. If you already know how to create pods with labels, you can skip this section.

Deploy Pod

kubectl run nginx-demo --image=nginx --port=80 --labels="name=nginx-demo"

Execute kubectl get pods to get status of the pod that was just created

rahil@k8s-master-node:~$ kubectl get pods
NAME                             READY     STATUS    RESTARTS   AGE
nginx-demo-74df6b89b6-lkjvq      1/1       Running   0          1m

Once the pod is created and it is in running status, we will go ahead and get started with services to create NodePort.

Create NodePort service

NodePort service exposes a port on every server that will redirect traffic to your pod. You can dynamically generate a port or assign static port as long as it is available.

Defining yaml file to create NodePort.

vi nginx-demo-nodeport-svc.yaml

Insert below details in above file.

apiVersion: v1
kind: Service
metadata:
  name: nginx-demo
  labels:
    name: nginx-demo-nodeport-svc
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30180
      name: http
    - port: 443
      nodePort: 31443
      name: https
  selector:
    name: nginx-demo

Let's create a deployment to create NodePort service.

kubectl create -f nginx-demo-nodeport-svc.yaml

Execute kubectl get services to get services for recently created service.

rahil@k8s-master-node:~$ kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP                      4d
nginx-demo   NodePort    10.98.148.146   <none>        80:30180/TCP,443:31443/TCP   1m

Once you have created a service you should see nginx-demo service created with ports that were defined in yaml file.

Now let's get the node IP where our pod is hosted. Then we can execute curl or browse it in browser.

kubectl get pods -o wide

output:

rahil@k8s-master-node:~$ kubectl get pods -o wide
NAME                             READY     STATUS    RESTARTS   AGE       IP            NODE
nginx-demo-74df6b89b6-lkjvq      1/1       Running   0          44m       10.244.1.15   k8s-worker-node1
$ nslookup k8s-worker-node1

Address: 192.168.0.151

Performing test

Using Curl:

rahil@k8s-master-node:~$ curl 192.168.0.151:30180
<!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>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

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

Browse in browser:
NodePort-service-expose-test-img

Using Command line to create NodePort service

kubectl expose deployment nginx-demo --port=80 --type=NodePort

Output:

rahil@k8s-master-node:~$ kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        4d
nginx-demo   NodePort    10.100.95.81    <none>        80:32546/TCP   4s

NOTE: When you create deployment for NodePort via command line, you cannot manually assign port. Cluster will automatically assign one dynamically. If you must assign port manually. Use yaml template and create a deployment.