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)

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.