Add transferring ownership section to api concepts

This commit is contained in:
Joe Betz
2020-07-07 09:30:59 -07:00
committed by zacharysarah
parent 71fa859471
commit 648508c051
4 changed files with 134 additions and 12 deletions
@@ -414,12 +414,6 @@ object or is [combined](#merge-strategy), by the server, with the existing objec
The system supports multiple appliers collaborating on a single object.
This model of specifying intent makes it difficult to remove existing fields.
When a field is removed from one's config and applied, the value will be kept
(the system assumes that you don't care about that value anymore). If an item is
removed from a list or a map, it will be removed if no other appliers care about
its presence.
Changes to an object's fields are tracked through a "[field management](#field-management)"
mechanism. When a field's value changes, ownership moves from its current
manager to the manager making the change. When trying to apply an object, fields
@@ -428,8 +422,14 @@ that have a different value and are owned by another manager will result in a
collaborator's changes. Conflicts can be forced, in which case the value will be
overridden, and the ownership will be transferred.
It is meant both as a replacement for the original `kubectl apply` and as a
simpler mechanism to write controllers.
If you remove a field from a configuration and apply the configuration, server side apply checks
if there are any other field managers that also own the field. If the field is
not owned by any other field managers, it is either deleted from the live
object or reset to its default value, if it has one. The same rule applies to associative list or
map items.
Server side apply is meant both as a replacement for the original `kubectl
apply` and as a simpler mechanism for controllers to enact their changes.
### Field Management
@@ -448,8 +448,12 @@ to the Server Side Apply endpoint. When using Server-Side Apply, trying to
change a field which is managed by someone else will result in a rejected
request (if not forced, see [Conflicts](#conflicts)).
Field management is stored in a newly introduced `managedFields` field that is
part of an object's
When two or more appliers set a field to the same value, they share ownership of
that field. Any subsequent attempt to change the value of the shared field, by any of
the appliers, results in a conflict. Shared field owners may give up ownership
of a field by removing it from their configuration.
Field management is stored in a`managedFields` field that is part of an object's
[`metadata`](/docs/reference/generated/kubernetes-api/{{< latest-version >}}/#objectmeta-v1-meta).
A simple example of an object created by Server Side Apply could look like this:
@@ -627,13 +631,88 @@ read-modify-write and/or patch are the following:
It is strongly recommended for controllers to always "force" conflicts, since they
might not be able to resolve or act on these conflicts.
### Transferring Ownership
In addition to the concurrency controls provided by [conflict
resolution](#conflicts), Server Side Apply provides ways to perform coordinated
field ownership transfers from users to controllers.
This is best explained by example. Let's look at how to safely transfer
ownership of the `replicas` field from a user to a controller while enabling
automatic horizontal scaling for a Deployment, using the HorizontalPodAutoscaler
resource and its accompanying controller.
Say a user has defined deployment with `replicas` set to the desired value:
{{< codenew file="application/ssa/nginx-deployment.yaml" >}}
And the user has created the deployment using server side apply like so:
```shell
kubectl apply -f application/ssa/nginx-deployment.yaml --server-side
```
Then later, HPA is enabled for the deployment, e.g.:
```
kubectl autoscale deployment nginx-deployment --cpu-percent=50 --min=1 --max=10
```
Now, the user would like to remove `replicas` from their configuration, so they
don't accidentally fight with the HPA controller. However, there is a race: it
might take some time before HPA feels the need to adjust `replicas`, and if
the user removes `replicas` before the HPA writes to the field and becomes
its owner, then apiserver will set `replicas` to 1, its default value. This
is not what the user wants to happen, even temporarily.
There are two solutions:
- (easy) Leave `replicas` in the configuration; when HPA eventually writes to that
field, the system gives the user a conflict over it. At that point, it is safe
to remove from the configuration.
- (more advanced) If, however, the user doesn't want to wait, for example
because they want to keep the cluster legible to coworkers, then they can take
the following steps to make it safe to remove `replicas` from their
configuration:
First, the user defines a new configuration containing only the `replicas` field:
{{< codenew file="application/ssa/nginx-deployment-replicas-only.yaml" >}}
The user applies that configuration using the field manager name `handover-to-hpa`:
```shell
kubectl apply -f application/ssa/nginx-deployment-replicas-only.yaml --server-side --field-manager=handover-to-hpa --validate=false
```
If the apply results in a conflict with the HPA controller, then do nothing. The
conflict just indicates the controller has claimed the field earlier in the
process that it sometimes does.
At this point the user may remove the `replicas` field from their configuration.
{{< codenew file="application/ssa/nginx-deployment-no-replicas.yaml" >}}
Note that whenever the HPA controller sets the `replicas` field to a new value,
the temporary field manager will no longer own any fields and will be
automatically deleted. No clean up is required.
### Transferring Ownership Between Users
Users can transfer ownership of a field between each other by setting the field
to the same value in both of their applied configs, causing them to share
ownership of the field. Once the users share ownership of the field, one of them
can remove the field from their applied configuration to give up ownership and
complete the transfer to the other user.
### Comparison with Client Side Apply
A consequence of the conflict detection and resolution implemented by Server
Side Apply is that an applier always has up to date field values in their local
state. If they don't, they get a conflict the next time they apply. Any of the
three options to resolve conflicts results in the applied config being an up to
date subset of the object on the server's fields.
three options to resolve conflicts results in the applied configuration being an
up to date subset of the object on the server's fields.
This is different from Client Side Apply, where outdated values which have been
overwritten by other users are left in an applier's local config. These values
@@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
@@ -0,0 +1,6 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
@@ -0,0 +1,19 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2