1
- # KEP-1959: Service Type=LoadBalancer Class Annotations
1
+ # KEP-1959: Service Type=LoadBalancer Class Field
2
2
3
3
<!-- toc -->
4
4
- [ Release Signoff Checklist] ( #release-signoff-checklist )
20
20
- [ Drawbacks] ( #drawbacks )
21
21
- [ Alternatives] ( #alternatives )
22
22
- [ ServiceClass Resource] ( #serviceclass-resource )
23
+ - [ Generic Annotation] ( #generic-annotation )
23
24
- [ Provider-Specific Annotations] ( #provider-specific-annotations )
24
25
- [ Infrastructure Needed (Optional)] ( #infrastructure-needed-optional )
25
26
<!-- /toc -->
@@ -49,14 +50,14 @@ Items marked with (R) are required *prior to targeting to a milestone / release*
49
50
When Service Type=LoadBalancer is enabled by a Kubernetes cloud provider, it is a global
50
51
configuration that applies for all Service Type=LoadBalancer resources in a given cluster.
51
52
This becomes problematic if users want to leverage multiple Service Type=LoadBalancer
52
- implementations in a given cluster.
53
+ implementations in a cluster.
53
54
54
55
The new [ Services APIs] ( https://github.com/kubernetes-sigs/service-apis ) addresses this already
55
56
with the GatewayClass resource. However, until Gateway/GatewayClass APIs become mature, we should
56
57
support similar functionality for Services of Type=LoadBalancer. Introducing a new resource like
57
58
` ServiceClass ` is probably not worthwhile given that there are new APIs already in development.
58
59
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 ` .
60
61
61
62
## Motivation
62
63
@@ -71,7 +72,8 @@ enable a lower-cost solution for workloads that are only internally accessible.
71
72
### Goals
72
73
73
74
* 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.
75
77
76
78
### Non-Goals
77
79
@@ -81,8 +83,8 @@ to disabling it from the cloud provider.
81
83
82
84
## Proposal
83
85
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.
86
88
87
89
### User Stories (Optional)
88
90
@@ -104,77 +106,103 @@ rely on protocols from hardware load balancers.
104
106
105
107
### Risks and Mitigations
106
108
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 .
110
112
111
113
## Design Details
112
114
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.
119
144
120
145
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.
125
148
126
149
### Test Plan
127
150
128
151
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.
131
156
132
157
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.
134
159
135
160
### Graduation Criteria
136
161
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).
138
167
139
168
### Upgrade / Downgrade Strategy
140
169
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).
150
174
151
175
### Version Skew Strategy
152
176
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.
154
179
155
180
## Implementation History
156
181
157
182
- the ` Summary ` , ` Motivation ` , ` Proposal ` and ` Design Details ` sections was merged, signaling SIG acceptance
158
183
159
184
## Drawbacks
160
185
161
- * Annotations are a clunky way to implement "Class" semantics to Service Type=LoadBalancer .
186
+ * Added complexity to Service.
162
187
* 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.
164
188
165
189
## Alternatives
166
190
167
191
### ServiceClass Resource
168
192
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.
172
200
173
201
### Provider-Specific Annotations
174
202
175
203
Instead of a generic Kubernetes annotation read by service controller, each cloud provider could implement
176
204
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.
178
206
179
207
## Infrastructure Needed (Optional)
180
208
0 commit comments