Skip to content

Commit 5c60202

Browse files
authored
Merge pull request #49976 from danwinship/endpoints-blog
KEP-4974 endpoints deprecation blog post for 1.33
2 parents 99deabf + f6f389f commit 5c60202

File tree

1 file changed

+228
-0
lines changed

1 file changed

+228
-0
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
---
2+
layout: blog
3+
title: "Continuing the transition from Endpoints to EndpointSlices"
4+
slug: endpoints-deprecation
5+
date: 2025-XX-XX
6+
draft: true
7+
author: >
8+
Dan Winship (Red Hat)
9+
---
10+
11+
Since the addition of [EndpointSlices] ([KEP-752]) as alpha in v1.15
12+
and later GA in v1.21, the
13+
Endpoints API in Kubernetes has been gathering dust. New Service
14+
features like [dual-stack networking] and [traffic distribution] are
15+
only supported via the EndpointSlice API, so all service proxies,
16+
Gateway API implementations, and similar controllers have had to be
17+
ported from using Endpoints to using EndpointSlices. At this point,
18+
the Endpoints API is really only there to avoid breaking end user
19+
workloads and scripts that still make use of it.
20+
21+
As of Kubernetes 1.33, the Endpoints API is now officially deprecated,
22+
and the API server will return warnings to users who read or write
23+
Endpoints resources rather than using EndpointSlices.
24+
25+
Eventually, the plan (as documented in [KEP-4794]) is to change the
26+
[Kubernetes Conformance] criteria to no longer require that clusters
27+
run the _Endpoints controller_ (which generates Endpoints objects
28+
based on Services and Pods), to avoid doing work that is unneeded in
29+
most modern-day clusters.
30+
31+
Thus, while the [Kubernetes deprecation policy] means that the
32+
Endpoints type itself will probably never completely go away, users
33+
who still have workloads or scripts that use the Endpoints API should
34+
start migrating them to EndpointSlices.
35+
36+
[EndpointSlices]: /blog/2020/09/02/scaling-kubernetes-networking-with-endpointslices/
37+
[KEP-752]: https://github.com/kubernetes/enhancements/blob/master/keps/sig-network/0752-endpointslices/README.md
38+
[dual-stack networking]: /docs/concepts/services-networking/dual-stack/
39+
[traffic distribution]: /docs/reference/networking/virtual-ips/#traffic-distribution
40+
[Kubernetes deprecation policy]: /docs/reference/using-api/deprecation-policy/
41+
[KEP-4974]: https://github.com/kubernetes/enhancements/blob/master/keps/sig-network/4974-deprecate-endpoints/README.md
42+
[Kubernetes Conformance]: https://www.cncf.io/training/certification/software-conformance/
43+
44+
## Notes on migrating from Endpoints to EndpointSlices
45+
46+
### Consuming EndpointSlices rather than Endpoints
47+
48+
For end users, the biggest change between the Endpoints API and the
49+
EndpointSlice API is that while every Service with a `selector` has
50+
exactly 1 Endpoints object (with the same name as the Service), a
51+
Service may have any number of EndpointSlices associated with it:
52+
53+
```console
54+
$ kubectl get endpoints myservice
55+
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
56+
NAME ENDPOINTS AGE
57+
myservice 10.180.3.17:443 1h
58+
59+
$ kubectl get endpointslice -l kubernetes.io/service-name=myservice
60+
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
61+
myservice-7vzhx IPv4 443 10.180.3.17 21s
62+
myservice-jcv8s IPv6 443 2001:db8:0123::5 21s
63+
```
64+
65+
In this case, because the service is dual stack, it has 2
66+
EndpointSlices: 1 for IPv4 addresses and 1 for IPv6 addresses. (The
67+
Endpoints API does not support dual stack, so the Endpoints object
68+
shows only the addresses in the cluster's primary address family.)
69+
Although any Service with multiple endpoints _can_ have multiple
70+
EndpointSlices, there are three main cases where you will see this:
71+
72+
- An EndpointSlice can only represent endpoints of a single IP
73+
family, so dual-stack Services will have separate EndpointSlices
74+
for IPv4 and IPv6.
75+
76+
- All of the endpoints in an EndpointSlice must target the same
77+
ports. So, for example, if you have a set of endpoint Pods
78+
listening on port 80, and roll out an update to make them listen
79+
on port 8080 instead, then while the rollout is in progress, the
80+
Service will need 2 EndpointSlices: 1 for the endpoints listening
81+
on port 80, and 1 for the endpoints listening on port 8080.
82+
83+
- When a Service has more than 100 endpoints, the EndpointSlice
84+
controller will split the endpoints into multiple EndpointSlices
85+
rather than aggregating them into a single excessively-large
86+
object like the Endpoints controller does.
87+
88+
Because there is not a predictable 1-to-1 mapping between Services and
89+
EndpointSlices, there is no way to know what the actual name of the
90+
EndpointSlice resource(s) for a Service will be ahead of time; thus,
91+
instead of fetching the EndpointSlice(s) by name, you instead ask for
92+
all EndpointSlices with a "`kubernetes.io/service-name`"
93+
[label](/docs/concepts/overview/working-with-objects/labels/) pointing
94+
to the Service:
95+
96+
```console
97+
$ kubectl get endpointslice -l kubernetes.io/service-name=myservice
98+
```
99+
100+
A similar change is needed in Go code. With Endpoints, you would do
101+
something like:
102+
103+
```go
104+
// Get the Endpoints named `name` in `namespace`.
105+
endpoint, err := client.CoreV1().Endpoints(namespace).Get(ctx, name, metav1.GetOptions{})
106+
if err != nil {
107+
if apierrors.IsNotFound(err) {
108+
// No Endpoints exists for the Service (yet?)
109+
...
110+
}
111+
// handle other errors
112+
...
113+
}
114+
115+
// process `endpoint`
116+
...
117+
```
118+
119+
With EndpointSlices, this becomes:
120+
121+
```go
122+
// Get all EndpointSlices for Service `name` in `namespace`.
123+
slices, err := client.DiscoveryV1().EndpointSlices(namespace).List(ctx,
124+
metav1.ListOptions{LabelSelector: discoveryv1.LabelServiceName + "=" + name})
125+
if err != nil {
126+
// handle errors
127+
...
128+
} else if len(slices.Items) == 0 {
129+
// No EndpointSlices exist for the Service (yet?)
130+
...
131+
}
132+
133+
// process `slices.Items`
134+
...
135+
```
136+
137+
### Generating EndpointSlices rather than Endpoints
138+
139+
For people (or controllers) generating Endpoints, migrating to
140+
EndpointSlices is slightly easier, because in most cases you won't
141+
have to worry about multiple slices. You just need to update your YAML
142+
or Go code to use the new type (which organizes the information in a
143+
slightly different way than Endpoints did).
144+
145+
For example, this Endpoints object:
146+
147+
```yaml
148+
apiVersion: v1
149+
kind: Endpoints
150+
metadata:
151+
name: myservice
152+
subsets:
153+
- addresses:
154+
- ip: 10.180.3.17
155+
nodeName: node-4
156+
- ip: 10.180.5.22
157+
nodeName: node-9
158+
- ip: 10.180.18.2
159+
nodeName: node-7
160+
notReadyAddresses:
161+
- ip: 10.180.6.6
162+
nodeName: node-8
163+
ports:
164+
- name: https
165+
protocol: TCP
166+
port: 443
167+
```
168+
169+
would become something like:
170+
171+
```yaml
172+
apiVersion: discovery.k8s.io/v1
173+
kind: EndpointSlice
174+
metadata:
175+
name: myservice
176+
labels:
177+
kubernetes.io/service-name: myservice
178+
addressType: IPv4
179+
endpoints:
180+
- addresses:
181+
- 10.180.3.17
182+
nodeName: node-4
183+
- addresses:
184+
- 10.180.5.22
185+
nodeName: node-9
186+
- addresses:
187+
- 10.180.18.12
188+
nodeName: node-7
189+
- addresses:
190+
- 10.180.6.6
191+
nodeName: node-8
192+
conditions:
193+
ready: false
194+
ports:
195+
- name: https
196+
protocol: TCP
197+
port: 443
198+
```
199+
200+
Some points to note:
201+
202+
1. This example uses an explicit `name`, but you could also use
203+
`generateName` and let the API server append a unique suffix. The name
204+
itself does not matter: what matters is the
205+
`"kubernetes.io/service-name"` label pointing back to the Service.
206+
207+
2. You have to explicitly indicate `addressType: IPv4` (or `IPv6`).
208+
209+
3. An EndpointSlice is similar to a single element of the `"subsets"`
210+
array in Endpoints. An Endpoints object with multiple subsets will
211+
normally need to be expressed as multiple EndpointSlices, each with
212+
different `"ports"`.
213+
214+
4. The `endpoints` and `addresses` fields are both arrays, but by
215+
convention, each `addresses` array only contains a single element. If
216+
your Service has multiple endpoints, then you need to have multiple
217+
elements in the `endpoints` array, each with a single element in its
218+
`addresses` array.
219+
220+
5. The Endpoints API lists "ready" and "not-ready" endpoints
221+
separately, while the EndpointSlice API allows each endpoint to have
222+
conditions (such as "`ready: false`") associated with it.
223+
224+
And of course, once you have ported to EndpointSlice, you can make use
225+
of EndpointSlice-specific features, such as topology hints and
226+
terminating endpoints. Consult the
227+
[EndpointSlice API documentation](/docs/reference/kubernetes-api/service-resources/endpoint-slice-v1)
228+
for more information.

0 commit comments

Comments
 (0)