# Kubernetes: what is Endpoints

---

Usually, we don’t see Endpoints objects when using Kubernetes Services, as they are working under the hood, similar to [ReplicaSets](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/) which are “hidden” behind Kubernetes Deployments.

### Kubernetes Service

So, [Service](https://kubernetes.io/docs/concepts/services-networking/service/) is a Kubernetes abstraction that uses *labels* to choose pods to route traffic to, see the [Kubernetes: ClusterIP vs NodePort vs LoadBalancer, Services, and Ingress — an overview with examples](https://rtfm.co.ua/en/kubernetes-clusterip-vs-nodeport-vs-loadbalancer-services-and-ingress-an-overview-with-examples/) and [Kubernetes: Service, load balancing, kube-proxy, and iptables](https://rtfm.co.ua/en/kubernetes-service-load-balancing-kube-proxy-and-iptables/):

```plaintext
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
```

As soon as a new pod appears in a cluster, with labels matching with Service’s `selector`, the `app=MyApp` in the example above - the 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:

```plaintext
---
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
```

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

Apply the manifest:

```plaintext
$ kubectl apply -f svc-example.yaml
pod/nginx-pod created
service/nginx-svc created
```

Check the Service:

```plaintext
$ 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
```

### Kubernetes Endpoints

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

```plaintext
$ 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
```

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

Check this Pod:

```plaintext
$ 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
…
```

Here is the IP mentioned above.

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

```plaintext
$ kubectl get endpoints nginx-svc
NAME ENDPOINTS AGE
nginx-svc 10.21.56.143:80 18m
```

If we 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:

```plaintext
---
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
```

Create the Deployment:

```plaintext
$ kubectl apply -f svc-example.yaml
deployment.apps/nginx-deploy created
service/nginx-svc unchanged
```

And check the Endpoints:

```plaintext
$ 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
```

Here we can see our *10.21.56.143:80* from the previous Pod and two new   ones 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:

```plaintext
$ 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
```

#### Custom Endpoint

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

For example, describe a new Service:

```plaintext
kind: Service
apiVersion: v1
metadata:
  name: external-svc
spec:
  ports:
    - name: web
      protocol: TCP
      port: 80
      targetPort: 80
```

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

And describe the Endpoints object:

```plaintext
kind: Endpoints
apiVersion: v1
metadata:
  name: external-svc
subsets: 
  - addresses:
        - ip: 139.59.205.180
    ports:
      - port: 80
        name: web
```

Here:

1. `name`: must be the same as the Service
    
2. `addresses`: an address to send traffic to, in this example, this is an IP address of a server in the DigitalOcean cloud where the [rtfm.co.ua](https://rtfm.co.ua/) is leaving, but you can set multiple address, so the Service will do load-balancing between them as described in the [Kubernetes: Service, load balancing, kube-proxy, and iptables](https://rtfm.co.ua/en/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:

```plaintext
$ 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
```

Run a Pod to check if this Service working:

```plaintext
$ kubectl run pod — rm -i — tty — image ubuntu — bash
```

Install the `curl` in this pod:

```plaintext
root@pod:/# apt update && apt -y install curl
```

And check the Service by its name:

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

Or by using its FQDN:

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

### `externalName`

Another solution to access an external resource can be using a Service with the [externalName](https://rtfm.co.ua/kubernetes-clusterip-vs-nodeport-vs-loadbalancer-services-i-ingress-obzor-primery/#ExternalName) type:

```plaintext
---
apiVersion: v1
kind: Service
metadata:
  name: rtfm-service
spec:
  ports:
    - port: 80
  type: ExternalName
  externalName: rtfm.co.ua
```

Apply, and check:

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

Done.

*Originally published at* [*RTFM: Linux, DevOps и системное администрирование*](https://rtfm.co.ua/en/kubernetes-what-is-endpoints/)*.*

---
