NodePort

kind: Service
apiVersion: v1
metadata:
  name: web-frontend
  labels:
    app.kubernetes.io/name: web-frontend
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: web-frontend
  ports:
    - port: 80
      name: http
      targetPort: 3000

Save the YAML contents to the nodeport-service.yaml file and run kubectl apply -f nodeport-service.yaml.

Once the service is created, run kubectl get svc - you will notice the service type has changed and the port number is random as well:

$ kubectl get svc
NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes     ClusterIP   10.96.0.1        <none>        443/TCP        16m
web-frontend   NodePort    10.107.154.215   <none>        80:30417/TCP   4s

To access this service we can use the external IP address of the nodes. So let's list the nodes first (we use -o wide to get the wide output that includes the IP addresses):

$ kubectl get nodes -o wide
NAME                                       STATUS   ROLES    AGE     VERSION            INTERNAL-IP   EXTERNAL-IP       OS-IMAGE                             KERNEL-VERSION   CONTAINER-RUNTIME
gke-cluster-1-default-pool-302e9aae-4jx2   Ready    <none>   7m37s   v1.19.9-gke.1400   10.138.0.13   104.199.120.171   Container-Optimized OS from Google   5.4.89+          containerd://1.4.3
gke-cluster-1-default-pool-302e9aae-dbwr   Ready    <none>   7m37s   v1.19.9-gke.1400   10.138.0.11   34.127.111.34     Container-Optimized OS from Google   5.4.89+          containerd://1.4.3
gke-cluster-1-default-pool-302e9aae-qvnf   Ready    <none>   7m35s   v1.19.9-gke.1400   10.138.0.12   35.233.187.108    Container-Optimized OS from Google   5.4.89+          containerd://1.4.3

Finally we can create a firewall rule to allow a specific node port on the node before we can access it. We can use gcloud CLI to do that (replace the [node-port] with the Kubernetes service node port value (e.g. 30417) and project name):

gcloud compute firewall-rules create test-node-port --allow tcp:[node-port] --project [your-gcp-project-name] 

If we pick any of the nodes IPs and try to curl to it, we'll get back the response from the Pods:

$ curl 34.127.111.34:30417
<link rel="stylesheet" type="text/css" href="css/style.css" />

<div class="container">
    Hello World!
</div> 

Make sure you delete the firewall rule:

gcloud compute firewall-rules delete  test-node-port --project [your-gcp-projet-name]

LoadBalancer

Let's delete the previous NodePort service with kubectl delete svc web-frontend.

kind: Service
apiVersion: v1
metadata:
  name: web-frontend
  labels:
    app.kubernetes.io/name: web-frontend
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/name: web-frontend
  ports:
    - port: 80
      name: http
      targetPort: 3000