DEV Community

Arseny Zinchenko
Arseny Zinchenko

Posted on • Originally published at rtfm.co.ua on

Kubernetes: what are Endpoints

Usually, we don’t see Endpoints objects when using Kubernetes Services, as they are working under the hood, similarly to ReplicaSets which are “hidden” behind Kubernetes Deployments.

Kubernetes Service

So, Service is a Kubernetes abstraction that uses labels to chose pods to route traffic to, see the Kubernetes: ClusterIP vs NodePort vs LoadBalancer, Services, and Ingress — an overview with examples and Kubernetes: Service, load balancing, kube-proxy, and iptables:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
Enter fullscreen mode Exit fullscreen mode

As soon as a new pod appears in a cluster, with labels matching with Service’s selector, the app=MyApp in the example above - Service will start sending traffic to it.

This is achieved by adding an IP address of this Pod to the Endpoints list of this Service.

Let’s create a simple example:

--------
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
    - name: nginx-container
      image: nginx
      ports:
        - name: web
          containerPort: 80
          protocol: TCP
--------
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
Enter fullscreen mode Exit fullscreen mode

Here, we are creating a Pod with NGINX, and a Service with the default type ClusterIP.

Apply the manifest:

$ kubectl apply -f svc-example.yaml
pod/nginx-pod created
service/nginx-svc created
Enter fullscreen mode Exit fullscreen mode

Check the Service:

$ kubectl get service nginx-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-svc ClusterIP 172.20.69.253 <none> 80/TCP 26s
Enter fullscreen mode Exit fullscreen mode

Kubernetes Endpoints

Now, let’s take a closer look at it:

$ kubectl describe service nginx-svc
Name: nginx-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Families: <none>
IP: 172.20.69.253
IPs: <none>
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.21.56.143:80
Enter fullscreen mode Exit fullscreen mode

In the end, we can the Endpoints of this Service — the IP of the pod.

Check this Pod:

$ kubectl describe pod nginx-pod
Name: nginx-pod
Namespace: default
Priority: 0
Node: ip-10–21–49–33.us-east-2.compute.internal/10.21.49.33
Start Time: Sat, 13 Mar 2021 08:37:55 +0200
Labels: app=nginx
Annotations: kubernetes.io/psp: eks.privileged
Status: Running
IP: 10.21.56.143
…
Enter fullscreen mode Exit fullscreen mode

Here is the IP mentioned above.

And now, let’s check the Ednpointds, which are dedicated API-objects and which can be observed in the same way as Services and Pods:

$ kubectl get endpoints nginx-svc
NAME ENDPOINTS AGE
nginx-svc 10.21.56.143:80 18m
Enter fullscreen mode Exit fullscreen mode

If we will add other pods with the same labels by describing them as additional objects in the manifest file or by creating a Deployment — those pods will be added as Endpoints for the Service:

--------
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-container
        image: nginx
        ports:
          - name: web
            containerPort: 80
            protocol: TCP
--------
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
Enter fullscreen mode Exit fullscreen mode

Create the Deployment:

$ kubectl apply -f svc-example.yaml
deployment.apps/nginx-deploy created
service/nginx-svc unchanged
Enter fullscreen mode Exit fullscreen mode

And check the Endpoints:

$ kubectl get endpoints nginx-svc
NAME ENDPOINTS AGE
nginx-svc 10.21.37.55:80,10.21.54.174:80,10.21.56.143:80 21m
Enter fullscreen mode Exit fullscreen mode

Here we can see our 10.21.56.143:80 from the previous pod, and two new — from the pods specified in the replicas of the Deployment above.

Find those pods by using the --selector, similarly, as a Service looks for pods to add them to its Endpoints:

$ kubectl get pod --selector=app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP
nginx-deploy-7fcd954c94-gbm6d 1/1 Running 0 2m28s 10.21.54.174
nginx-deploy-7fcd954c94-mg8kr 1/1 Running 0 2m28s 10.21.37.55
nginx-pod 1/1 Running 0 23m 10.21.56.143
Enter fullscreen mode Exit fullscreen mode

Custom Endpoint

We also can create a custom endpoint that will be pointed to any desired resource.

For example, describe a new Service:

kind: Service
apiVersion: v1
metadata:
  name: external-svc
spec:
  ports:
    - name: web
      protocol: TCP
      port: 80
      targetPort: 80
Enter fullscreen mode Exit fullscreen mode

Pay attention, that in this case, we didn’t add the selector field.

And describe the Endpoints object:

kind: Endpoints
apiVersion: v1
metadata:
  name: external-svc
subsets: 
  - addresses:
        - ip: 139.59.205.180
    ports:
      - port: 80
        name: web
Enter fullscreen mode Exit fullscreen mode

Here:

  1. name: must be the same as the Service
  2. addresses: an address to send traffic to, in this example this an IP address of a server in the DigitalOcean cloud where the rtfm.co.ua is leaving, but you can set multiply address so the Service will do load-balancing between them as described in the Kubernetes: Service, load balancing, kube-proxy, and iptables
  3. ports.port and ports.name also must be the same as the corresponding Service

Create them:

$ kubectl apply -f external-endpoint.yaml
service/external-svc created
endpoints/external-svc created
Check the Service and its Endpoints:
kubectl describe svc external-svc
Name: external-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP Families: <none>
IP: 172.20.45.77
IPs: <none>
Port: web 80/TCP
TargetPort: 80/TCP
Endpoints: 139.59.205.180:80
Enter fullscreen mode Exit fullscreen mode

Run a Pod to check if this Service working:

$ kubectl run pod — rm -i — tty — image ubuntu — bash
Enter fullscreen mode Exit fullscreen mode

Install the curl in this pod:

root@pod:/# apt update && apt -y install curl
Enter fullscreen mode Exit fullscreen mode

And check the Service by its name:

root@pod:/# curl -Ls external-svc | grep \<title\>
<title>RTFM: Linux, DevOps, and system administration</title>
Enter fullscreen mode Exit fullscreen mode

Or by using its FQDN:

root@pod:/# curl -Ls external-svc.default.svc.cluster.local | grep \<title\>
<title>RTFM: Linux, DevOps, and system administration</title>
Enter fullscreen mode Exit fullscreen mode

externalName

Another solution to access an external resource can be using a Service with the externalName type:

--------
apiVersion: v1
kind: Service
metadata:
  name: rtfm-service
spec:
  ports:
    - port: 80
  type: ExternalName
  externalName: rtfm.co.ua
Enter fullscreen mode Exit fullscreen mode

Apply, and check:

$ root@pod:/# curl -Ls rtfm-service | grep \<title\>
<title>RTFM: Linux, DevOps, and system administration</title>
Enter fullscreen mode Exit fullscreen mode

Done.

Originally published at RTFM: Linux, DevOps и системное администрирование.


Top comments (0)