K8s KnowHow: Using A Service
Now that we have run a Spring Boot app in a pod, the second part of this series will demonstrate how to expose that pod.
Join the DZone community and get the full member experience.
Join For FreeThis is the second article of the Kubernetes Knowhow series. In this article, we will see how to expose a pod to the outside world. In the last article https://dzone.com/articles/k8s-knowhow-running-first-pod-1, we learned how to run a Spring Boot sample application in a pod. We also learned to start an interactive shell in order to access pod. However, we could not access the welcome url from outside of K8s cluster, for an instance from the browser, a Rest client. Now, the next step is to expose this pod outside of K8s cluster. Let’s get started!
I will start with our pod definition.
K8s pods are mortal. In addition, each pod gets its own IP address and IP addresses are not fixed. That means IP addresses are not relied upon. For instance, if the pod is restarted then it is quite possible that pod gets a different IP address in a subsequent run. In addition, the pod is not visible outside the K8s cluster. So what is the solution? Service comes to our rescue.
K8s service is an abstraction that defines a logical set of pods and policy by which to access them. Service is a REST object just like a pod and has an endpoint so that service can be accessed from outside provided type supports visibility. What the heck does it mean? It implies that even Service can be hidden from the outside world. Let us first understand service types.
In the current version of K8s, the following four service types are supported.
- ClusterIP – Exposes the service on cluster internal IP. That means the service is accessible inside the cluster only. This is the default service type.
- NodePort – Exposes the service outside. This is something extremely useful to us considering the purpose of the article. With the NodePort service type K8s exposes the service on Node’s IP at fixed static port. A ClusterIP service, to which the NodePort service will route, is automatically created. In addition, NodePort service is accessible from outside at <NodeIP>:<NodePort>.
- LoadBalancer – Exposes the service externally using a cloud provider’s load balancer. NodePort and ClusterIP services, to which the external load balancer will route, are automatically created.
- ExternalName – Maps the service to the contents of the externalName field (e.g. foo.bar.example.com), by returning a CNAME record with its value.
We will see NodePort with scrupulous attention at the end of this article.
Let us first see the service definition in order to expose above pod (refer to pod definition above).
Tag |
Type |
Description |
apiVersion |
String |
Versioned schema of represented objects |
kind |
String |
REST resource that the object represents – Pod, Service, Deployment. In service definition, its Service |
metadata |
ObjectMeta |
Details about metadata of an object |
name |
metadata |
It’s a unique name within the namespace |
spec |
ServiceType |
It defines the behavior of a service |
selector |
Spec |
It is an extremely important attribute as it is the one that is used to match the pod running in the cluster. Route service traffic to pods with label keys and values matching this selector. Now, in order to match with the pod label, you require to have the exact, key and value pair. In our example, its app: hello-world-webapp. Now, if you change the key to mylablename, then you will see that even if you use same value i.e hello-world-webapp, then value of service becomes ZERO. That is why it is important to meticulously design the service definition. |
spec |
ServiceSpec |
ServiceSpec defines the behavior of a service |
ports |
spec |
It’s a ServicePort array. The list of ports that are exposed by this service |
name |
spec: ports |
The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. This maps to the 'Name' field in EndpointPort objects |
port |
spec:ports |
The port that will be exposed by this service. It’s the internal port on which service is exposed. For an instance, in our hello world spring application |
nodePort |
spec:ports |
The port that will be available outside K8s cluster. Service is available on this port on the node. This setting makes the service visible outside the Kubernetes cluster by the node’s IP address and the port number declared in this property |
type |
spec |
Type of the service – ClusterIP, NodePort, LoadBalancer, ExternalName |
K8s reserves a nodePort on all its nodes. All nodes that running the Service's pods have this port open. Now, this is happening because of Kube-Proxy, ipTable, and routing. Kube-Proxy uses the ipTables to resolve the requests coming on a specific nodePort and redirect them to appropriate pods. Kubernetes master allocates a port from a range specified by the --service-node-port-range
flag (default: 30000-32767), and each Node will proxy that port (the same port number on every Node) into your Service. That port will be reported in service’s .spec.ports[*].nodePort field.
A NodePort exposes the following:
- <NodeIP>:spec.ports[*].nodePort
- spec.clusterIp:spec.ports[*].port
Now it’s time to get into some action. Let us apply the changes pertaining to the service configuration. I am assuming that pod is up and running as follows.
Now get the IP address of the cluster and hit the browser. Navigate to http://<minikube_ip_address>:31080/welcome and you should see the welcome page.
Just to summarize, K8s Service is the abstraction that allows pods to die and replicate in Kubernetes without affecting your application. A Service routes traffic across a set of Pods. Discovery and routing among dependent Pods are handled by Kubernetes Services.
Opinions expressed by DZone contributors are their own.
Comments