Kubernetes - Services

Kubernetes Service

Service is an abstract way to expose an application running on a set of Pods as a network service.

Every pod has an IP address. A Pod’s IP address is ephemeral because the pods can failed and replaced in a different node. Service has a stable and reliable IP address that you can use to access the pods.

Service Types

There are three Service Typs to choose from.

  • ClusterIP: Exposes the Service on a cluster-internal IP. Choosing this value makes the Service only reachable from within the clluster. This is the default ServiceType
  • NodePort: Exposes the service on each Node’s IP at a static port(the NodePort). A ClusterIP Service, to which the NodePort Service routes, is automatically created. You will be able to contact the NodePort Service, from outside the cluster, by requesting <NodeIP>:<NodePort>. The drawback of NodePort is you need to know the node’s ip address to access the service.
  • LoadBalancer: Exposes the service externally using a cloud provider’s load balancer. If the cluster is not run on the cloud, then LoadBalancer type is probably not supported.

Service Commands

To get a list of services exposed

1
kubectl get services

To describe a service named nginx

1
kubectl describe service nginx

Delete a service

1
kubectl delete service nginx

Expose a resource( can be pod, replicaset, service, deployment) as a new Kubernetes service.

1
2
3
# Create a service for an nginx deployment, which serves on port 80 and connects to the containers on port 8000.
kubectl expose deployment nginx --port=80 --target-port=8000

ClusterIP

You can only access this service while inside the cluster. ClusterIP is usually used by backend service and data store service.

Sample service with ClusterIP type

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: ClusterIP
selector:
app: myapp
ports:
- protocol: TCP
targetPort: 80
port: 8080

A service use selectors to select the pods with specific labels.

Here there are two ports defined

  • targetPort - the port to access on the pods targeted by the service. This is the port which the application is configured to listen on.
  • port - the port that wil be exposed by this service

Use kubectl get services to list service info

1
2
3
4
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 103m
myapp ClusterIP 10.101.67.7 <none> 8080/TCP 15s

When inside the cluster, you can access this service suing the following

  • clusterIP:port

Example to access the service inside the cluster

1
curl 10.101.67.7:8080

One way to get into a cluster is to execute kubectl exec -it <pod-name> /bin/bash command to get into a pod. You may need to install curl in the pod if it is not available. In addition, curl installation doesn’t always work.

Note that another way to access the application is port forwarding.

NodePort

NodePort exposes the service via the defined note port. The service can be reach on any node in the cluster via the nodePort.

myapp-service.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: NodePort
selector:
app: myapp
ports:
- protocol: TCP
targetPort: 80
port: 8080
nodePort: 30003

Here there are three ports defined

  • targetPort - the port to access on the pods targeted by the service
  • port - the port that wil be exposed by this service
  • nodePort - The port on each node on which this service is exposed when type=NodePort or LoadBalancer. Usually assigned by the system.

Use kubectl get services to list service info

1
2
3
4
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 106m
myapp NodePort 10.101.67.7 <none> 8080:30003/TCP 3m3s

You can access this service using the following

  • clusterIP:port
  • nodeIP:nodePort

In addition to accessing the service using clusterIP, you can access the service outside of the cluster using node’s external IP. For minikube cluster, the node’s external IP can be retrieved using minikube ip command.

1
curl 172.17.0.44:30003

You can get a node’s ip using kubectl get nodes -o wide command

LoadBalancer

Loadbalancer exposes the service to the outside world.

Sample LoadBalancer type service

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: LoadBalancer
selector:
app: myapp
ports:
- protocol: TCP
targetPort: 80
port: 8080
nodePort: 30003

Here there are three ports defined

  • targetPort - the port to access on the pods targeted by the service
  • port - the port that wil be exposed by this service
  • nodePort - The port on each node on which this service is exposed when type=NodePort or LoadBalancer. Usually assigned by the system.

Use kubectl get services to list service info

1
2
3
4
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 109m
myapp LoadBalancer 10.101.67.7 172.17.0.22 8080:30003/TCP 6m18s

You can access this service using the following

  • clusterIP:port
  • nodeIP:nodePort
  • loadBalancerIp:port

Example to access the service using loadbalancerIP outside of the cluster. Kubernetes routes request to a nodePort, then routes to the clusterIP port.

1
curl 172.17.0.22:8080

Service Discovery via DNS

As of Kubernetes v1.12, CoreDNS is the recommended DNS Server, replacing kube-dns. However, kube-dns may still be installed by default with certain Kubernetes installer tools. Both the CoreDNS and kube-dns Service are named kube-dns in the metadata.name field.

When inside a Kubernetes cluster, you can use ClusterIP or DNS to visit the service. DNS Service will resolve the DNS name.

Every Service defined in the cluster is assigned a DNS A Record. The record is of format <Service-name>.<Namespace>.svc.<Cluster-Domain>. You can often use <Service-name>.<Namespace> to refer to the service.

So in the application code, use url http://service-name.namespace/ to visit the service. Kubernetes will resolve the hostname using dns service.

servicediscovery.yml: A pod that uses DNS name to visit myapp service.

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Pod
metadata:
name: servicetest
labels:
name: servicetest
spec:
restartPolicy: Never
containers:
- name: servicetest
image: byrnedo/alpine-curl
command: [ "/bin/sh", "-c", "curl http://myapp.default:8080;"]

This pod refers to myapp service in default namespace using hostname myapp.default. The complete dns name for myapp service is myapp.default.svc.cluster.local. cluster.local is the default Namespace can be omitted if the service provider and consumer are in the same namespace.

Execute the following command to see how the pod visit the service using DNS name.

1
2
$ kubectl apply -f servicediscovery.yml 
$ kubectl logs servicetest

Port Forwarding

Service is not the only way to access an application. One way is to use port forwarding to access a pod.

port-forwarding allows you to forward a local port in the host to a port on the pod

1
kubectl port-forward <pod-name> <local-port>:<port>

You can use curl hostname:host-port to access the pod locally. Default hostname is localhost if address option is not set.

kubctl port-forward has an option --address to specify the address to listen on. It accepts IP addresses or localhost as a value. Default is localhost.

For more details on port forwarding, use kubectl port-forward --help command to see sample usage. See Port Forwarding documentation for more detail explaination.

Reference