Server-side Apply and Field Ownership
Two field managers write the same Deployment, so who wins and how does the API know? Server-side apply records a field manager for every field an actor sets, keeping that ledger in managedFields, and an apply that stops sending a field it owns removes it unless another manager owns it too. A second manager applying the same field with a different value raises a conflict the API refuses until forced, and that record replaces the client-side three-way merge.
Play the animation 6 steps, animated, best on a wide screen
Server-side Apply and Field Ownership, step by step
-
You run kubectl apply --server-side, a PATCH sent with the content type application/apply-patch+yaml. Every apply has to name a field manager, and kubectl sends the name kubectl by default. The API records that name against every field the request sets, so all four fields of Deployment web end up owned by kubectl.
Play from step 1 -
The ledger sits on the object under metadata.managedFields, one entry per manager and operation: the name, Apply or Update, the apiVersion and a fieldsV1 tree of the paths it owns. It stays hidden unless you ask kubectl for json or yaml output and pass --show-managed-fields. Non-apply writes land here as operation Update, where the name is optional and the API infers it from the User-Agent.
Play from step 2 -
Delete spec.minReadySeconds from the file and apply again. The API compares the request against what you owned last time, so a field you stop sending is deleted from the live object, or reset to its default if it has one. That happens only when no other manager owns it too. If one does, you drop out of that entry and the value stays.
Play from step 3 -
A scaling controller applies spec.replicas 5 under the field manager name scale-controller, but kubectl owns that field at 3, so the API refuses the whole request with HTTP 409 and names the conflict. Nothing on the object changes. A plain update never fails this way, it takes the field quietly and your next apply is what finds out.
Play from step 4 -
Repeating it with --force-conflicts sets force=true in the query and the apply lands: spec.replicas becomes 5 and the field moves from kubectl to scale-controller. Controllers are told to force on objects they own, since they may not be able to resolve one. Two appliers setting the same value share the field, and the next change by either conflicts.
Play from step 5 -
This is what server-side apply replaces. Plain kubectl apply keeps your file in the kubectl.kubernetes.io/last-applied-configuration annotation, then runs a three-way merge across the annotation, the file and the live object on your own machine. Removals are found by reading the annotation, so a value another actor wrote is invisible to it.
Play from step 6