Understanding Service Without Selector and EndpointSlice Behavior in Kubernetes

Hi Team,

I’m new to Kubernetes and have a question regarding the behavior of Endpoints and EndpointSlice in Kubernetes. After reviewing multiple pieces of documentation, I found that every Service in Kubernetes needs an associated Endpoints, which contains a group of IPs, and these are further split into EndpointSlices to optimize networking, especially in large clusters.

From what I gathered, Kubernetes automatically creates Endpoints and EndpointSlice resources for a Service when the Service is deployed and has a selector.

Now, here’s my specific scenario and question:

I have a custom SMTP server that I need to reach from my Kubernetes cluster. To achieve this, I created a Service without a selector and set clusterIP: None. I then deployed an Endpoints YAML file (not an EndpointSlice). Upon doing so, Kubernetes automatically created an EndpointSlice, and everything worked as expected—I was able to reach the SMTP server successfully.

However, while reviewing the Kubernetes documentation on services without selectors, I noticed it mentions that creating a Service and an associated EndpointSlice should work seamlessly. But when I tried this approach, the IPs mentioned in the EndpointSlice were not allocated to the Service, and I couldn’t reach the SMTP server.

Here are my questions:

  1. Is my understanding of how Services, Endpoints, and EndpointSlice interact (with and without selectors) correct?
  2. Why does the functionality fail when I rely solely on a manually created EndpointSlice as described in the documentation?
  3. The documentation refers to Endpoints as “legacy.” Can someone clarify what this means and whether there are specific scenarios where EndpointSlice cannot fully replace Endpoints?

Cluster information:

Kubernetes version:
Client Version: v1.30.3
Server Version: v1.30.5-gke.1713000
Cloud being used: GKE
Installation method: gcloud CLI
Host OS: Container-Optimized OS
CNI and version: fluent-bit:v1.8.12-gke.46
CRI and version: containerd://1.7.23

Details of the Endpoints and Endpointslice Yaml that i used for testing purposes
(Using a dummy IP for reference purposes)

Endpoint.yaml

apiVersion: v1
kind: Endpoints
metadata:
  name: smtp
subsets:
  - addresses:
      - ip: 192.00.00.01
      - ip: 192.00.00.01
    ports:
      - name: http
        port: 587

Service.yaml

apiVersion: v1
kind: Service
metadata:
  name: smtp
spec:
  clusterIP: None
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 587

Endpointslice.yaml

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: smtp
  namespace: test-green
  labels:
    kubernetes.io/service-name: smtp
    app: smtp
    endpointslice.kubernetes.io/managed-by: devops-managed
addressType: IPv4
ports:
  - name: http
    protocol: TCP
    port: 587
endpoints:
  - addresses:
      - 192.00.00.01
    conditions:
      ready: true
  - addresses:
      - 192.00.00.01
    conditions:
      ready: true

Thanks
Srimathi S

I am confused - you said “everything worked as expected—I was able to reach the SMTP server” and then “when I tried this approach, the IPs mentioned in the EndpointSlice were not allocated to the Service”

What did you change between those two states?

Hi Thockin

2 approaches i tried,

  1. Creating a Service and Endpoints automatically generates an EndpointSlice, and everything works as expected.
  2. Creating only a Service and an EndpointSlice , no endpoints are created, resulting in no endpoints being available in the service.

Does the first approach guarantee the correct behavior?

While following documentation for the second approach, it didn’t work as expected. Should I also create Endpoints manually with the Service and EndpointSlice to resolve the issue?(2)
Which approach is ideal?

I see. I am AFK at the moment, so can’t cite exactly, but endpoints ↔ endpointslice mirroring is done by distinct logic, and there are some conditions for when it is known to be safe.

FWIW Endpoints is all-but-dead. It’s not going to be removed, but we want to emphasize that EndpointSlice is the normal way to do things.

just to clarify, if this is created without errors,
have you checked with the correct namespace kubectl get endpointslice -

Yes!.

But, When using EndpointSlice and service deployments, I’m unable to reach the IPs specified in the EndpointSlice from the mapped services. So preferring endpoints and services deployments here!

May i know what is wrong with implementation as per documentation approach?

Name:              smtp
Namespace:         test
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP Family Policy:  RequireDualStack
IP Families:       IPv4,IPv6
IP:                None
IPs:               None
Port:              http  80/TCP
TargetPort:        587/TCP
Endpoints:         <none>
Session Affinity:  None
Events:            <none>

Failed to send email: 0.130988

Yes!
It was created successfully without any errors and is listed only in the deployed namespace (endpoints,endpointslice and service)

Hi Thockin,

Based on the below documentation, mirroring happens from endpoints resource to endpointslice

If your statement “EndpointSlice is the normal way to do things.” is right, then shouldn’t mirroring occur in the opposite way.
Currently I’m also facing the same issue where if I create Headless service without selector and it’s respective Endpointslice manually, my service is not getting updated with the endpoints when I describe it and it’s also not resolving.
But it’s working if I create a Headless service without selector and it’s respective Endpoints manually.

If K8s is planning to move to Endpointslice, then shouldn’t I be able to achieve this through Endpointaslice and mirroring should happen in the opposite way. What are we missing here?

Thanks