Kubernetes: Services

created:

updated:

tags: kubernetes

Kubernetes services enable communication between various components within and outside of the application. The services enable loose coupling between microservices in the application. In order for the end user to access the application on the web browser, Kubernetes service is necessary.

External communication

How does an external user access our application?

  • ssh or curl nto Kubernetes node IP address (from inside Kubernetes node)
  • Without ssh or curl, we can use Kubernetes services

Kubernetes Services Types

  • NodePort service: to listen to a port on the node and forward requests on that port to the port running on the pod.
    • Internal pod accessible on a port on the node.
  • ClusterIP service: service creates virtual IP address inside cluster to communicate with different services.
  • Load balancer service: provisions a load balancer for the application in supported cloud providers.

NodePort

Maps a port on the node to a port on a pod.

  • TargetPort: a port where the service forwards the requests to.
  • Port: port on the service. Service is like a virtual server in the node, inside the cluster, it has its own IP address.
    • This IP address is called the cluster IP of the service.
  • NodePort: a port where users can use to access the web server externally.
    • Valid IP range: 30000 to 32767

How to create a Kubernetes Service

# service-definition.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  type: NodePort
  ports:
    - targetPort: 80
      port: 80  # port on the service object
      nodePort: 30008
  selector:
    app: myapp  # from pod_definition.yaml
    type: front-end  # from pod_definition.yaml
  • If we don’t provide targetPort, Kubernetes service will assume it’s the same as port.
  • If we don’t provide nodePort, Kubernetes service will automatically assign a free port in the valid range
  • Similar to other Kubernetes objects, we can use selector to map the service to a pod

Command

kubectl create -f service-definition.yaml
# Create a service of type of NodePort to expose the pod's port 80 on port 30080 on the nodes
# This uses the pod's labels as selectors but cannot specify the node port
kubectl expose pod <pod name> --port=<pod port> --name <name of service> --type=NodePort --dry-run=client -o yaml
# Or
# this will not use the pods' labels as selectors
kubectl create service nodeport <pod name> --tcp=<service_port>:<target_pod_port> --node-port=30080 --dry-run=client -o yaml
  • Suggestion from KodeKloud: Use kubectl expose
    • “If you need to specify a node port, generate a definition file using the same command and manually input the nodeport before creating the service.”
kubectl get services
kubectl get svc
# for minkube
# it prints the URL where the service is availble
minikube service myapp-service --url

After creating the service

  • We can access the pod via curl or on the web browser by accessing the IP address of the node and use the nodePort (30008)

What do we do when we have multiple pods in a node?

In production environment, we have several pods running for high availability and load balancing purposes. These pods can have the same labels. The same labels can be used as a selector during creation of Kubernetes service. The service looks for matching pods with the same label. Then it selects all the matching pods as endpoints to forward the external request.

Load balancing algorithm

  • It uses a ‘random algorithm’.
  • distribute the load across different pods.

What do we do when we have pods distributed across multiple nodes?

Kubernetes automatically creates a service that spans across all the nodes in the cluster and maps the targetPort to the same nodePort on all the nodes in the cluster. This way, we can access the application via any of IP address of nodes in the cluster and the same port number (30008).

Cluster IP Service

THe IP address of pods are not static, they can change when pods are created or removed. A Kubernetes service help us group the pods together and provide a single interface to access the pods in a group.

  • ex: backend service, redis service
  • This is helpful to deploy a microservice-based application on Kubernetes cluster.
  • Each layer of service can scale or move without impcating the communication between various services.
  • Each service gets an IP address and name assigned to it within the cluster and the name is used by other pods to access the service.

Create cluser IP service

apiVersion: v1
kind: Service
metadata:
  name: back-end
spec:
  type: ClusterIP
  ports:
    - targetPort: 80  # port where the backend is exposed
      port: 80  # port where the service is exposed
  selector:
    app: myapp
    type: back-end
kubectl create -f service-definition.yaml
# Dry run a creation of a service of type ClusterIP without a definition file
# This will use the pod's labels as selectors automatically
kubectl expose pod <name of pod> --port=<port> --name <name of service> --dry-run-client -o yaml
# Or
# This will assume selectors as `app=redis`
kubectl create service clusterip <name> --tcp=<service_port>:<target_container_port> --dry-run=client -o yaml
  • The service can be accessed by other pods using the cluster IP or the service name.

Load Balancer Service

  • The services with type NodePort helps in receiving traffic on the ports and routing traffic to corresponding pods.
  • Users prefer a single well-defined URL like example.com, abc.com to access the application.

Ways to have a load balancer

  • to create a new VM for load balancer purpose and install and configure a load balancer such as proxy or nginx to route traffic to underlining nodes
    • This can be a tedious work
  • If we use a cloud platform such as Google Cloud, AWS, or Azure, we can leaverage the native load balancer of the cloud platform with Kubernetes.
    • Kubernetes support integration with the native load balancers on cloud platforms.
    apiVersion: v1
    kind: Service
    metadata: myapp-service
    spec:
      type: LoadBalancer
      ports:
        - targetPort: 80
          port: 80
          nodePort: 30008
    
    • If we use type: LoadBalancer and the environment does not have the native load balancer provided by the unsupported cloud platform, the Kubernetes LoadBalancer service will act like NodePort

Endpoints

Service identifies pods via labels and once the pods are identified, the service has endpoints to the pods.

  • There may be multiple pods with the same label, and the endpoints can be helpful to identify what pods are existing.
  • Endpoints are available in the description of Kubernetes service.
  • Endpoints are specification of pods based on selector and labels.

Summary

Whether it’s a single pod in a single node, multiple pods in a single node, or multiple pods in multiple nodes, Kubernetes service is created the same without further configuration. When pods are removed or added, the service is automatically updated.

References