Skip to content

Commit 5065bf9

Browse files
authored
Merge pull request #27379 from apelisse/improve-ssa-docs
SSA Toplogy improvements
2 parents d5f3d74 + acfea6f commit 5065bf9

File tree

1 file changed

+65
-8
lines changed

1 file changed

+65
-8
lines changed

content/en/docs/reference/using-api/server-side-apply.md

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -224,17 +224,75 @@ merging, see
224224
A number of markers were added in Kubernetes 1.16 and 1.17, to allow API
225225
developers to describe the merge strategy supported by lists, maps, and
226226
structs. These markers can be applied to objects of the respective type,
227-
in Go files or in the OpenAPI schema definition of the
227+
in Go files or in the OpenAPI schema definition of the
228228
[CRD](/docs/reference/generated/kubernetes-api/{{< param "version" >}}#jsonschemaprops-v1-apiextensions-k8s-io):
229229

230230
| Golang marker | OpenAPI extension | Accepted values | Description | Introduced in |
231231
|---|---|---|---|---|
232-
| `//+listType` | `x-kubernetes-list-type` | `atomic`/`set`/`map` | Applicable to lists. `atomic` and `set` apply to lists with scalar elements only. `map` applies to lists of nested types only. If configured as `atomic`, the entire list is replaced during merge; a single manager manages the list as a whole at any one time. If `set` or `map`, different managers can manage entries separately. | 1.16 |
233-
| `//+listMapKey` | `x-kubernetes-list-map-keys` | Slice of map keys that uniquely identify entries for example `["port", "protocol"]` | Only applicable when `+listType=map`. A slice of strings whose values in combination must uniquely identify list entries. While there can be multiple keys, `listMapKey` is singular because keys need to be specified individually in the Go type. | 1.16 |
232+
| `//+listType` | `x-kubernetes-list-type` | `atomic`/`set`/`map` | Applicable to lists. `set` applies to lists that include only scalar elements. These elements must be unique. `map` applies to lists of nested types only. The key values (see `listMapKey`) must be unique in the list. `atomic` can apply to any list. If configured as `atomic`, the entire list is replaced during merge. At any point in time, a single manager owns the list. If `set` or `map`, different managers can manage entries separately. | 1.16 |
233+
| `//+listMapKey` | `x-kubernetes-list-map-keys` | List of field names, e.g. `["port", "protocol"]` | Only applicable when `+listType=map`. A list of field names whose values uniquely identify entries in the list. While there can be multiple keys, `listMapKey` is singular because keys need to be specified individually in the Go type. The key fields must be scalars. | 1.16 |
234234
| `//+mapType` | `x-kubernetes-map-type` | `atomic`/`granular` | Applicable to maps. `atomic` means that the map can only be entirely replaced by a single manager. `granular` means that the map supports separate managers updating individual fields. | 1.17 |
235235
| `//+structType` | `x-kubernetes-map-type` | `atomic`/`granular` | Applicable to structs; otherwise same usage and OpenAPI annotation as `//+mapType`.| 1.17 |
236236

237-
### Custom Resources
237+
If `listType` is missing, the API server interprets a
238+
`patchMergeStrategy=merge` marker as a `listType=map` and the
239+
corresponding `patchMergeKey` marker as a `listMapKey`.
240+
241+
The `atomic` list type is recursive.
242+
243+
These markers are specified as comments and don't have to be repeated as
244+
field tags.
245+
246+
### Compatibility across topology changes
247+
248+
On rare occurences, a CRD or built-in type author may want to change the
249+
specific topology of a field in their resource without incrementing its
250+
version. Changing the topology of types, by upgrading the cluster or
251+
updating the CRD, has different consequences when updating existing
252+
objects. There are two categories of changes: when a field goes from
253+
`map`/`set`/`granular` to `atomic` and the other way around.
254+
255+
When the `listType`, `mapType`, or `structType` changes from
256+
`map`/`set`/`granular` to `atomic`, the whole list, map or struct of
257+
existing objects will end-up being owned by actors who owned an element
258+
of these types. This means that any further change to these objects
259+
would cause a conflict.
260+
261+
When a list, map, or struct changes from `atomic` to
262+
`map`/`set`/`granular`, the API server won't be able to infer the new
263+
ownership of these fields. Because of that, no conflict will be produced
264+
when objects have these fields updated. For that reason, it is not
265+
recommended to change a type from `atomic` to `map`/`set`/`granular`.
266+
267+
Take for example, the custom resource:
268+
269+
```yaml
270+
apiVersion: example.com/v1
271+
kind: Foo
272+
metadata:
273+
name: foo-sample
274+
managedFields:
275+
- manager: manager-one
276+
operation: Apply
277+
apiVersion: example.com/v1
278+
fields:
279+
f:spec:
280+
f:data: {}
281+
spec:
282+
data:
283+
key1: val1
284+
key2: val2
285+
```
286+
287+
Before `spec.data` gets changed from `atomic` to `granular`,
288+
`manager-one` owns the field `spec.data`, and all the fields within it
289+
(`key1` and `key2`). When the CRD gets changed to make `spec.data`
290+
`granular`, `manager-one` continues to own the top-level field
291+
`spec.data` (meaning no other managers can delete the map called `data`
292+
without a conflict), but it no longer owns `key1` and `key2`, so another
293+
manager can then modify or delete those fields without conflict.
294+
295+
## Custom Resources
238296

239297
By default, Server Side Apply treats custom resources as unstructured data. All
240298
keys are treated the same as struct fields, and all lists are considered atomic.
@@ -245,7 +303,7 @@ that contains annotations as defined in the previous "Merge Strategy"
245303
section, these annotations will be used when merging objects of this
246304
type.
247305

248-
### Using Server-Side Apply in a controller
306+
## Using Server-Side Apply in a controller
249307

250308
As a developer of a controller, you can use server-side apply as a way to
251309
simplify the update logic of your controller. The main differences with a
@@ -260,7 +318,7 @@ read-modify-write and/or patch are the following:
260318
It is strongly recommended for controllers to always "force" conflicts, since they
261319
might not be able to resolve or act on these conflicts.
262320

263-
### Transferring Ownership
321+
## Transferring Ownership
264322

265323
In addition to the concurrency controls provided by [conflict resolution](#conflicts),
266324
Server Side Apply provides ways to perform coordinated
@@ -329,7 +387,7 @@ Note that whenever the HPA controller sets the `replicas` field to a new value,
329387
the temporary field manager will no longer own any fields and will be
330388
automatically deleted. No clean up is required.
331389

332-
## Transferring Ownership Between Users
390+
### Transferring Ownership Between Users
333391

334392
Users can transfer ownership of a field between each other by setting the field
335393
to the same value in both of their applied configs, causing them to share
@@ -458,4 +516,3 @@ Server Side Apply is a beta feature, so it is enabled by default. To turn this
458516
you need to include the `--feature-gates ServerSideApply=false` flag when
459517
starting `kube-apiserver`. If you have multiple `kube-apiserver` replicas, all
460518
should have the same flag setting.
461-

0 commit comments

Comments
 (0)