Skip to content

Commit 4ba7d87

Browse files
committed
update to use field loadBalancerClassName
Signed-off-by: Andrew Sy Kim <[email protected]>
1 parent acb5ec5 commit 4ba7d87

File tree

2 files changed

+72
-44
lines changed

2 files changed

+72
-44
lines changed

keps/sig-cloud-provider/1959-service-lb-class-annotation/README.md renamed to keps/sig-cloud-provider/1959-service-lb-class-field/README.md

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# KEP-1959: Service Type=LoadBalancer Class Annotations
1+
# KEP-1959: Service Type=LoadBalancer Class Field
22

33
<!-- toc -->
44
- [Release Signoff Checklist](#release-signoff-checklist)
@@ -20,6 +20,7 @@
2020
- [Drawbacks](#drawbacks)
2121
- [Alternatives](#alternatives)
2222
- [ServiceClass Resource](#serviceclass-resource)
23+
- [Generic Annotation](#generic-annotation)
2324
- [Provider-Specific Annotations](#provider-specific-annotations)
2425
- [Infrastructure Needed (Optional)](#infrastructure-needed-optional)
2526
<!-- /toc -->
@@ -49,14 +50,14 @@ Items marked with (R) are required *prior to targeting to a milestone / release*
4950
When Service Type=LoadBalancer is enabled by a Kubernetes cloud provider, it is a global
5051
configuration that applies for all Service Type=LoadBalancer resources in a given cluster.
5152
This becomes problematic if users want to leverage multiple Service Type=LoadBalancer
52-
implementations in a given cluster.
53+
implementations in a cluster.
5354

5455
The new [Services APIs](https://github.com/kubernetes-sigs/service-apis) addresses this already
5556
with the GatewayClass resource. However, until Gateway/GatewayClass APIs become mature, we should
5657
support similar functionality for Services of Type=LoadBalancer. Introducing a new resource like
5758
`ServiceClass` is probably not worthwhile given that there are new APIs already in development.
5859
This KEP proposes a light-weight approach for Service Type=LoadBalancer by introducing a Service
59-
annotation `service.kubernetes.io/load-balancer-class`.
60+
field `service.spec.loadBalancerClassName`.
6061

6162
## Motivation
6263

@@ -71,7 +72,8 @@ enable a lower-cost solution for workloads that are only internally accessible.
7172
### Goals
7273

7374
* allow users to opt-out of the Service Type=LoadBalancer implementation by the cloud provider.
74-
* allow multiple implementations of Service Type=LoadBalancer in a given cluster.
75+
* allow multiple implementations of Service Type=LoadBalancer in a cluster.
76+
* prevent every cloud provider from implementing a custom "opt-out" annotation for their load balancer.
7577

7678
### Non-Goals
7779

@@ -81,8 +83,8 @@ to disabling it from the cloud provider.
8183

8284
## Proposal
8385

84-
This KEP proposes to add a new Service annotation `service.kubernetes.io/load-balancer-class`
85-
that allows for multiple implementations of Service Type=LoadBalancer in a cluster.
86+
This KEP proposes to add a new field `spec.loadBalancerClassName` in Service which allows for
87+
multiple implementations of Service Type=LoadBalancer in a cluster.
8688

8789
### User Stories (Optional)
8890

@@ -104,77 +106,103 @@ rely on protocols from hardware load balancers.
104106

105107
### Risks and Mitigations
106108

107-
Many Service Type=LoadBalancer implementations today support a lot of knobs via annotations already.
108-
Introducing yet another annotation for Service Type=LoadBalancer is not ideal, but this is better than
109-
every cloud provider supporting their own "skip this Service" annotation.
109+
Many cloud providers today support an "opt-out" annotation for this behavior. The annotation is specific
110+
to the cloud provider. Introduction of the `loadBalancerClassName` field at this point would mean that
111+
cloud providers need to start accounting for both existing annotations and the new field.
110112

111113
## Design Details
112114

113-
Introduce a new Service annotation `service.kubernetes.io/load-balancer-class`.
114-
115-
If the loadbalancer class annotation is not set, the existing cloud provider
116-
will assume ownership of the Service Type=LoadBalancer resource. This is required
117-
to not break existing clusters that assume Service Type=LoadBalancer is always
118-
managed by the cloud provider.
115+
Introduce a new field to Service `spec.loadBalancerClassName`.
116+
117+
If the field `spec.loadBalancerClassName` is not set, the existing cloud provider will assume
118+
ownership of the Service Type=LoadBalancer resource. This is required to not break existing clusters
119+
that assume Service Type=LoadBalancer is always managed by the cloud provider.
120+
121+
Required API changes:
122+
```go
123+
// ServiceSpec describes the attributes that a user creates on a service.
124+
type ServiceSpec struct {
125+
...
126+
...
127+
128+
// loadBalancerClassName is the name of the load balancer implementation this Service belongs to.
129+
// This field can only be set when the Service type is 'LoadBalancer'. If not set, the default load
130+
// balancer implementation is used, today this is typically done through the cloud provider integration,
131+
// but should apply for any default implementation. If set, it is assumed that a load balancer
132+
// implementation is watching for Services with a matching class name. Any default load balancer
133+
// implementation (e.g. cloud providers) should ignore Services that set this field.
134+
// +optional
135+
LoadBalancerClassName string `json:"loadBalancerClassName,omitempty"`
136+
}
137+
```
138+
139+
* `loadBalancerClassName` will be immutable so that existing and future implementations do not have to worry
140+
about handling Services that change the class name.
141+
* `loadBalancerClassName` can carry arbitrary string values.
142+
* the `loadBalancerClassName` field will be feature gated. The field will be dropped during API strategy unless
143+
the feature gate is enabled.
119144

120145
Required updates to service controller:
121-
* if the class annotation is NOT set for a Service, allow the cloud provider
122-
to reconcile the load balancer.
123-
* if the class annotation IS set for a Service, skip reconciliation of the Service
124-
by the cloud provider.
146+
* if the class field is NOT set for a Service, allow the cloud provider to reconcile the load balancer.
147+
* if the class annotation IS set for a Service, skip reconciliation of the Service from the cloud provider.
125148

126149
### Test Plan
127150

128151
Unit tests:
129-
* test that service controller does not call the cloud provider if the class annotation is set.
130-
* the annotation `service.kubernetes.io/load-balancer-class` is not accepted when the feature gate `ServiceLoadBalancerClass` is disabled.
152+
* test that service controller does not call the cloud provider if the class field is set.
153+
* test API strategy to ensure the `loadBalancerClassName` field is dropped unless the feature gate is enabled
154+
or an existing Service has the field set.
155+
* test API validation for immutability.
131156

132157
E2E tests:
133-
* test that creating a Service with an unknown class annotation results in no load balancer being created for a Service.
158+
* test that creating a Service with an unknown class name results in no load balancer being created for a Service.
134159

135160
### Graduation Criteria
136161

137-
N/A since we can't apply alpha/beta/GA criteria for annotations.
162+
Alpha:
163+
* the `loadBalancerClassName` field is added to Service with an alpha feature gate.
164+
* when enabled, service controller will ignore Service LBs with a non-empty class name.
165+
* unit tests for service controller.
166+
* unit tests for API strategy (drop disabled fields).
138167

139168
### Upgrade / Downgrade Strategy
140169

141-
On upgrade, use of this annotation will be allowed. On downgrade, service controller
142-
may ignore existing Services with the annotation, leading to multiple implementations
143-
trying to create load balancers. On downgrade, if the class annotation is used
144-
and there are multiple implementations of Service Type=LoadBalancer, a user must ensure
145-
there is only 1 implementation of Service Type=LoadBalancer in the cluster.
146-
147-
Though the downgrade scenario isn't ideal, it is assumed if that a cluster was upgraded to v1.20,
148-
and already has multiple Service Type=LoadBalancer implementations enabled, it will likely not be
149-
downgrading to v1.19 anytime soon.
170+
* Usage of `loadBalancerClassName` will be off by default during the alpha stage but can handle existing Services that
171+
has the field set already. This ensures apiserver can handle the new field on downgrade.
172+
* On upgrade, if the feature gate is enabled, there should be no changes since the default behavior has not changed
173+
(service controller calls the cloud provider to reconcile load balancers).
150174

151175
### Version Skew Strategy
152176

153-
N/A since this only impacts one component.
177+
Since this feature will be alpha for at least 1 release, an n-1 kube-controller-manager or cloud-controller-manager should
178+
handle enablement of this feature if a new apiserver enabled it.
154179

155180
## Implementation History
156181

157182
- the `Summary`, `Motivation`, `Proposal` and `Design Details` sections was merged, signaling SIG acceptance
158183

159184
## Drawbacks
160185

161-
* Annotations are a clunky way to implement "Class" semantics to Service Type=LoadBalancer.
186+
* Added complexity to Service.
162187
* In **most** clusters, a single Service Type=LoadBalancer implementation from the cloud provider is sufficient.
163-
* The potential risks during downgrade can cause outages if Service Status is updated by the wrong load balancer implementation.
164188

165189
## Alternatives
166190

167191
### ServiceClass Resource
168192

169-
Similar to GatewayClass and IngressClass, we could introduce a new resource so that multiple implementations of
170-
Service Type=LoadBalancer can exist, however, a new resource just for Service Type=LoadBalancer seems unnecessary,
171-
especially if GatewayClass will satisfy this use-case better in the near future.
193+
Instead of a field specifying the name of the implemmentation, the class name can reference the name of a class resource
194+
similar to GatewayClass and IngressClass. This would enable more expressive configuration per load balancer implementation.
195+
196+
### Generic Annotation
197+
198+
A generic annotation can be used to store the class name. This is avoided since there would be no way to introduce
199+
the annotation in a safe way and we can't enforce immutability for annotations.
172200

173201
### Provider-Specific Annotations
174202

175203
Instead of a generic Kubernetes annotation read by service controller, each cloud provider could implement
176204
their own "skip this Service"-like logic with custom annotations. Given that many cloud providers have been
177-
asking for this feature, a generic well-known annotation used across all providers may be more beneficial.
205+
asking for this feature, a generic field used across all providers may be more beneficial.
178206

179207
## Infrastructure Needed (Optional)
180208

Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
title: Service Type=LoadBalancer Class Annotation
1+
title: Service Type=LoadBalancer Class Field
22
kep-number: 1959
33
authors:
44
- "@andrewsykim"
55
owning-sig: sig-cloud-provider
66
participating-sigs:
77
- sig-network
88
status: implementable
9-
creation-date: 2020-08-31
9+
creation-date: 2020-11-02
1010
reviewers:
1111
- "@bowei"
1212
- "@cheftako"
@@ -19,14 +19,14 @@ prr-approvers:
1919
- "@johnbelamaric"
2020

2121
# The target maturity stage in the current dev cycle for this KEP.
22-
stage: stable
22+
stage: alpha
2323

2424
# The most recent milestone for which work toward delivery of this KEP has been
2525
# done. This can be the current (upcoming) milestone, if it is being actively
2626
# worked on.
27-
latest-milestone: "v1.20"
27+
latest-milestone: "v1.21"
2828

2929
# The milestone at which this feature was, or is targeted to be, at each stage.
3030
milestone:
31-
stable: "v1.20"
31+
alpha: "v1.21"
3232

0 commit comments

Comments
 (0)