Kubernetes Services

What is Kubernetes Services?

Being a resource will create a single, constant point of a group of Pods behind it. Each service will have a constant IP address and port, unless we delete it and create it again. The client will open a connection to the service, and that connection will be directed to one of the Pods in the background.

So what problems does service help us with? Each Pod also has its own IP address, so why don't we call it directly instead of going through the service without wasting time? To answer these questions, we will go over a few issues.

Pods are ephemeral

This means that a Pod is a very ephemeral resource, it will be created, deleted, and replaced with another at any time. Maybe when we want to change a different template for the Pod, the old Pod will be deleted. and the new Pod will be created. Or in case a woker node dies, the Pod on that worker node will also die, and a new Pod will be created on another woker node.

When creating a new pod, it will have a different IP from the old one. If we use the Pod's IP to create a connection to the client, then when the Pod is replaced with another IP, we must update the code.

Multiple Pod run same application

This means we will have many pods running one of our applications to increase performance. For example, when we use ReplicaSet with replicas = 3, it will create 3 Pods. So how do we know which Pod to send requests to?

To solve the above problems, Kubernetes provides us with Services resource , the Service will create a constant endpoint for the Pods behind, the client only needs to interact with this endpoint.

How does the service manage connection?

How does the Service know which Pod it will choose to manage connections to those Pods, if you remember label selectors from previous articles and how ReplicaSet uses labels to manage Pods. Services will also use label selectors to select the Pod that manages the connection.

Sample config

apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello-kube # label selectors Pod
  ports:
    - port: 80 # port of the serivce
      targetPort: 3000 # port of the container that service will forward to 

Service will have 4 basic types:

  • ClusterIP

  • NodePort

  • ExternalName

  • LoadBalancer

ClusterIP

This type of service will create an IP and local DNS that will be accessible inside the cluster, not accessible from the outside, used mainly for Pods inside the cluster to easily communicate with each other.

For example, we have an application that needs to use redis, we will deploy a redis Pod and our application needs to connect to that redis Pod. With redis, its connection string will look like this redis://<host-name>:<port>, so how will our application connect to redis? Next we will make an example of creating Pod redis and Service for it.

Create a file named hello-service.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - image: redis # redis image
        name: redis
        ports:
          - containerPort: 6379

---
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  selector:
    app: redis # label selectors Pod redis
  ports:
    - port: 6379 # port of the serivce
      targetPort: 6379 # port of the container that service will forward to 

kubectl apply -f hello-service.yaml

Now our redis will have the following access address redis://10.100.255.140:6379 . We can see that the hostname of our service here is 10.100.255.140 , we can use this address so that applications we deploy later can access the redis host.

So if we have applications already running, how can we connect to this host, or do we have to update the code? So to solve this problem, instead of accessing the redis host via IP, we can access it via DNS, kubernes provides us with a local DNS inside the cluster, helping us connect to our host. want to go through DNS. We can connect to redis with the following address redis://redis:6379 , with host name being the name of the Service we put in the metadata field .

Test the service. You can create a Pod to test using the config file

apiVersion: v1
kind: Pod
metadata:
  name: application
spec:
  containers:
    - image: 080196/hello-redis
      name: application

Or create using cli for quick

kubectl run hello-redis --image=080196/hello-redis

This is the application code in 080196/hello-redis image

const redis = require("redis");

const client = redis.createClient("redis://redis:6379")

client.on("connect", () => {
  console.log("Connect redis success");
})

Check the pod's log, if it prints Connect redis success , we have connected to the redis host using DNS

kubectl logs hello-redis

Clear resource

kubectl delete pod hello-redis
kubectl delete -f hello-service.yaml

ClusterIP helps applications deployed in our cluster communicate with each other much easier. What if we want external clients to be able to access our application? There are 3 ways: using NodePort, LoadBalancer (supports cloud), Ingress.

NodePort

This is the first way to expose the Pod so that external clients can access the Pod inside the cluster. Like ClusterIP, NodePort will also create an accessible endpoint inside the cluster by IP and DNS, and it will use a port of the entire worker node so that external clients can communicate with our Pod via through that port. NodePort will have a default range from 30000 - 32767. For example:

apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello-kube
  type: NodePort # type NodePort
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30123 # port of the worker node

Clients can send requests to Pod using the address 130.211.97.55:30123 or 130.211.99.206:30123 . And the application inside the cluster can send requests to the Pod with the address http://hello-kube

Now let's create a NodePort service. Create a file named hello-nodeport.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: hello-rs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-kube
  template:
    metadata:
      labels:
        app: hello-kube
    spec:
      containers:
      - image: 080196/hello-kube
        name: hello-kube
        ports:
          - containerPort: 3000

---
apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello-kube
  type: NodePort
  ports:
    - port: 3000
      targetPort: 3000
      nodePort: 31000

kubectl apply -f hello-nodeport.yaml

Test sends request to Pod with addresshttp://<your_worker_node_ip>:<node_port>

LoadBalancer

When you run kubernetes on the cloud, it will support LoadBalancer Service. If you run on an environment that does not support LoadBalancer, you cannot create this type of Service. When you create a LoadBalancer Service, it will create a public IP for us, so that clients can access the Pod inside the Cluster using this public IP address. For example

apiVersion: v1
kind: Service
metadata:
  name: kubia-loadbalancer
spec:
  selector:
    app: kubia
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 8080

Ingress resource

Ingress is a resource that allows us to expose HTTP and HTTPS routes from outside the cluster to services inside our cluster. Ingress will help us assign an actual domain to a service inside the cluster. For example:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  rules:
    - host: kubia.example.com # domain name
  http:
    paths:
      - path: /
        backend:
          serviceName: kubia-nodeport # name of the service inside cluster
          servicePort: 80

We can also map multiple services to the same domain. For example:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  rules:
    - host: kubia.example.com
  http:
    paths:
      - path: /bar
        backend:
          serviceName: kubia-bar
          servicePort: 80
      - path: /foo
        backend:
          serviceName: kubia-foo
          servicePort: 80

Ingress is the most useful resource to expose Pod's HTTP and HTTPS to the outside. You can read more about Ingress here .

Last updated