Introduction
Kubernetes is an open-source platform for automating deployment, scaling, and operations of application containers across clusters of hosts. It’s a powerful tool for microservices architecture and has become a cornerstone of container orchestillation. One of the main features of Kubernetes is the Service object, which provides an abstract way to expose an application running on a set of Pods as a network service. In this tutorial, we will cover how to expose applications using Kubernetes Services thereby making them accessible to external traffic and other services inside or outside of a cluster.
Understanding Kubernetes Services
In Kubernetes, a Service is an abstraction which defines a logical set of Pods and a policy by which to access them. This abstraction enables loose coupling between dependent Pods. The set of Pods targeted by a Service is usually determined by a selector. Types of Services include:
- ClusterIP: Exposes the Service on an internal IP in the cluster. This type of Service is reachable only within the cluster.
- NodePort: Exposes the Service on the same port of each selected Node in the cluster using NAT. It makes a cluster service reachable externally, although the IP is not stable.
- LoadBalancer: Exposes the Service externally using a cloud provider’s load balancer. NodePort and ClusterIP Services, to which the external load balancer routes, are automatically created.
- ExternalName: Maps the Service to the contents of the externalName field by returning a CNAME record with its value. No proxying of any kind is set up.
Creating a Basic Service
The busiest element of a Kubernetes service is the Pod, which encapsulates application containers. Here’s how to create a simple Service that exposes a Pod.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
After creating the YAML file, apply it using the kubectl command:
$ kubectl apply -f my-service.yaml
Output:
service/my-service created
Exposing a Service via NodePort
Let’s move towards making our Service accessible externally through a NodePort.
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
type: NodePort
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
nodePort: 30007
targetPort: 9376
After updating the Service definition, apply it:
$ kubectl apply -f my-nodeport-service.yaml
Output:
service/my-nodeport-service created
You can then access your application externally using any of your nodes’ IP addresses combined with the NodePort. Assuming your Node IP is 192.168.1.2, access it via:
http://192.168.1.2:30007
Using a LoadBalancer Service
In a cloud environment, you likely want to use a LoadBalancer service. Here’s a simple example for that.
apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
spec:
type: LoadBalancer
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
Deploy it as follows:
$ kubectl apply -f my-loadbalancer-service.yaml
Output:
service/my-loadbalancer-service created
The LoadBalancer service is provisioned with an external IP address by your cloud provider. You can list the details of the Service to get the IP:
$ kubectl get services my-loadbalancer-service
Output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-loadbalancer-service LoadBalancer 10.0.171.239 203.0.113.1 80:31377/TCP 78s
This external IP (203.0.113.1) is what you’d use to access your service from outside the Kubernetes cluster.
Defining a Service Without Selectors
There may be situations where you want to define Services without selectors such as when you want to manage the Pods’ lifecycle manually. For that, you create endpoints manually.
apiVersion: v1
kind: Service
metadata:
name: my-manual-service
spec:
ports:
- protocol: TCP
port: 80
Apply this definition and create an endpoint:
$ kubectl apply -f my-manual-service.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: my-manual-service
subsets:
- addresses:
- ip: 192.168.1.2
ports:
- port: 9376
After creating the endpoints, your Service should route to the specified Pod IP address.
Debugging Kubernetes Services
Sometimes, exposed services may not work as expected. Common ways to debug services include checking Logs, the Events tab in Kubernetes Dashboard, or running descriptions for detailed information.
$ kubectl describe service my-service
$ kubectl logs [pod-name]
Accessing Services from Other Applications
Within the cluster, other applications may need to communicate with the service. Kubernetes supports service discovery and request routing by assigning a stable IP address and DNS name for the service, which routes to any of the service’s Pods.
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx
env:
- name: SERVICE_NAME
value: my-service
In this Pod, applications could connect to the ‘my-service’ through environment variables or DNS.
Conclusion
Services in Kubernetes offer a powerful abstraction for exposing applications running in Pods to be accessible as a network service. Using the correct type of Service depending on your environment and requirements is crucial. With this understanding, scaling and operating applications become much more manageable.