Skip to content

Commit 1b1def8

Browse files
authored
Merge pull request #13 from cloudscale-ch/denis/additional-documentation
Add traffic policy and expected impacts of changes to docs
2 parents 8c294bc + d6188e7 commit 1b1def8

File tree

2 files changed

+220
-15
lines changed

2 files changed

+220
-15
lines changed

README.md

Lines changed: 220 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ kubectl expose deployment hello \
8585
--name=hello \
8686
--type=LoadBalancer \
8787
--port=80 \
88-
--target-port=80 \
88+
--target-port=80
8989
```
9090

9191
Afterward, wait for the external IP to become available:
@@ -218,15 +218,229 @@ The full set of configuration toggles can be found in the [`pkg/cloudscale_ccm/l
218218

219219
These annotations are all optional, as they come with reasonable defaults.
220220

221-
### Preserve Client Source IP
221+
### External Traffic Policy: Local
222222

223-
By default, the source IP seen in the target container is not the original source IP of the client.
223+
By default, Kubernetes adds an extra hop between load balancer and the pod that handles a packet. The load balancer sends packets to all nodes and the nodes implement balancing using NAT, adding an additional hop.
224224

225-
To change this, see the official Kubernetes documentation:
225+
In some cases, the extra hop is undesireable or unnecessary. In this case, the external traffic policy can be set to local:
226226

227-
https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
227+
```yaml
228+
apiVersion: v1
229+
kind: Service
230+
spec:
231+
externalTrafficPolicy: Local
232+
```
233+
234+
With this policy, the load balancer only sends traffic to nodes that have at least one of the necessary pods, and Kubernetes will only send traffic to the pods local to the node.
235+
236+
This is accomplished by an additional health monitor added by the CCM, which checks a `/livez` endpoint provided by the node. If the endpoint returns an HTTP 200, at least one targeted pod is available on the node.
237+
238+
### Client Source IP
239+
240+
Because traffic setup via CCM goes through our load balancers, you do not see the client source IP. To get access to the client's IP, you can configure your service to use the `proxy` or `proxyv2` protocol, which is supported by web servers like [NGINX](https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/).
241+
242+
```yaml
243+
apiversion: v1
244+
kind: Service
245+
metadata:
246+
annotations:
247+
k8s.cloudscale.ch/loadbalancer-pool-protocol: proxyv2
248+
```
249+
250+
See https://kubernetes.io/docs/reference/networking/service-protocols/#protocol-proxy-special
251+
252+
### Impact of Service Changes
253+
254+
The CCM reacts to service changes by changing the load balancer configuration.
255+
256+
Depending on the change, this can have a bigger or a smaller impact. While we try to be as efficient and non-disruptive as possible, we often have to apply generic actions to safely get to the desired state.
257+
258+
What follows is a list of changes that you might want to apply to an existing service, with a description of the expected impact.
259+
260+
You can get detailed information about each annotation here in the [`pkg/cloudscale_ccm/loadbalancer.go`](pkg/cloudscale/ccm/loadbalancer.go) file.
261+
262+
> :warning: We recommend using testing environments and maintenance windows to avoid surprises when changing configuration.
263+
264+
#### No Impact
265+
266+
The following annotations can be changed safely at any time, and should not impact any active or new connections:
267+
268+
- `k8s.cloudscale.ch/loadbalancer-timeout-client-data-ms`
269+
- `k8s.cloudscale.ch/loadbalancer-timeout-member-connect-ms`
270+
- `k8s.cloudscale.ch/loadbalancer-timeout-member-data-ms`
271+
- `k8s.cloudscale.ch/loadbalancer-name` (though we recommend to not change it).
272+
273+
#### Minimal Impact
274+
275+
Changes to the CIDRs is generally safe, but may impact new connections if they do not match the CIDR:
276+
277+
- `k8s.cloudscale.ch/loadbalancer-listener-allowed-cidrs`
278+
279+
Floating IP changes are also safe, but they should be applied with care:
280+
281+
- `k8s.cloudscale.ch/loadbalancer-floating-ips`
282+
283+
Changes to following annotations may lead to new connections timing out until the change is complete:
284+
285+
- `k8s.cloudscale.ch/loadbalancer-health-monitor-delay-s`
286+
- `k8s.cloudscale.ch/loadbalancer-health-monitor-timeout-s`
287+
- `k8s.cloudscale.ch/loadbalancer-health-monitor-up-threshold`
288+
- `k8s.cloudscale.ch/loadbalancer-health-monitor-down-threshold`
289+
- `k8s.cloudscale.ch/loadbalancer-health-monitor-type`
290+
- `k8s.cloudscale.ch/loadbalancer-health-monitor-http`
291+
292+
##### Listener Port Changes
293+
294+
Changes to the outward bound service port have a downtime ranging from 15s to 120s, depending on the action. Since the name of the port is used to avoid expensive pool recreation, the impact is minimal if the port name does not change.
295+
296+
For example, the following port 80 to port 8080 change should cause downtime of no more than 15s, as the implicit name of "" is not changed:
297+
298+
<table>
299+
<thead><tr><th>Before</th><th>After</th></tr></thead>
300+
<tbody><tr><td>
301+
302+
```yaml
303+
apiVersion: v1
304+
kind: Service
305+
spec:
306+
ports:
307+
- port: 80
308+
protocol: TCP
309+
targetPort: 80
310+
```
311+
312+
</td>
313+
<td>
314+
315+
```yaml
316+
apiVersion: v1
317+
kind: Service
318+
spec:
319+
ports:
320+
- port: 8080
321+
protocol: TCP
322+
targetPort: 80
323+
```
324+
325+
</td></tr></tbody></table>
326+
327+
If the name is made explicit, the same rule applies and we should not see downtime of more than 15s:
328+
329+
<table>
330+
<thead><tr><th>Before</th><th>After</th></tr></thead>
331+
<tbody><tr><td>
332+
333+
```yaml
334+
apiVersion: v1
335+
kind: Service
336+
spec:
337+
ports:
338+
- port: 80
339+
protocol: TCP
340+
targetPort: 80
341+
name: http
342+
```
343+
344+
</td>
345+
<td>
346+
347+
```yaml
348+
apiVersion: v1
349+
kind: Service
350+
spec:
351+
ports:
352+
- port: 8080
353+
protocol: TCP
354+
targetPort: 80
355+
name: http
356+
```
357+
358+
</td></tr></tbody></table>
359+
360+
Adding and removing ports should also not impact any ports that are unaffected by the change.
361+
362+
However, the following change causes a pool to be recreated and therefore a downtime of 60s-120s is estimated:
363+
364+
<table>
365+
<thead><tr><th>Before</th><th>After</th></tr></thead>
366+
<tbody><tr><td>
367+
368+
```yaml
369+
apiVersion: v1
370+
kind: Service
371+
spec:
372+
ports:
373+
- port: 80
374+
protocol: TCP
375+
targetPort: 80
376+
name: http
377+
```
378+
379+
</td>
380+
<td>
381+
382+
```yaml
383+
apiVersion: v1
384+
kind: Service
385+
spec:
386+
ports:
387+
- port: 443
388+
protocol: TCP
389+
targetPort: 80
390+
name: https
391+
```
392+
393+
</td></tr></tbody></table>
394+
395+
Same goes for this change, where the default name of "" is changed. This is the most surprising example and underscores why it is generally a good idea to plan some maintenance, even if the expected impact is minor:
396+
397+
<table>
398+
<thead><tr><th>Before</th><th>After</th></tr></thead>
399+
<tbody><tr><td>
400+
401+
```yaml
402+
apiVersion: v1
403+
kind: Service
404+
spec:
405+
ports:
406+
- port: 80
407+
protocol: TCP
408+
targetPort: 80
409+
```
410+
411+
</td>
412+
<td>
413+
414+
```yaml
415+
apiVersion: v1
416+
kind: Service
417+
spec:
418+
ports:
419+
- port: 80
420+
protocol: TCP
421+
targetPort: 80
422+
name: http
423+
```
424+
425+
</td></tr></tbody></table>
426+
427+
#### Considerable Impact
428+
429+
Changes to the following annotations causes pools to be recreated and cause an estimated downtime of 60s-120s.
430+
431+
- `k8s.cloudscale.ch/loadbalancer-pool-algorithm`
432+
- `k8s.cloudscale.ch/loadbalancer-pool-protocol`
433+
- `k8s.cloudscale.ch/loadbalancer-listener-allowed-subnets`
434+
435+
Additionally, changes to `spec.externalTrafficPolicy` have the same effect.
436+
437+
#### Major Impact
438+
439+
Changes to the following annotations are not allowed by the CCM and can only be implemented by deleting and re-creating the service. This is due to the fact that these changes would cause a load balancer to be re-created, causing major downtime and the loss of the currently associated IP address (with the exception of the Floating IP):
228440

229-
The mentioned `externalTrafficPolicy: Local` setting on the service spec is fully supported.
441+
- `k8s.cloudscale.ch/loadbalancer-flavor` (may be supported in the future).
442+
- `k8s.cloudscale.ch/loadbalancer-zone`
443+
- `k8s.cloudscale.ch/loadbalancer-vip-addresses`
230444

231445
# Developer Manual
232446

examples/nginx-hello.yml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,6 @@ spec:
3030
containers:
3131
- name: hello
3232
image: nginxdemos/hello:plain-text
33-
34-
# Spread the containers across nodes
35-
topologySpreadConstraints:
36-
- maxSkew: 1
37-
topologyKey: kubernetes.io/hostname
38-
whenUnsatisfiable: DoNotSchedule
39-
labelSelector:
40-
matchLabels:
41-
app: hello
4233
---
4334
apiVersion: v1
4435
kind: Service

0 commit comments

Comments
 (0)