argo-cd icon indicating copy to clipboard operation
argo-cd copied to clipboard

Server-Side Apply prevents field deletion owned by other managers

Open pjiang-dev opened this issue 7 months ago • 2 comments

Checklist:

  • [x] I've searched in the docs and FAQ for my answer: https://bit.ly/argocd-faq.
  • [x] I've included steps to reproduce the bug.
  • [x] I've pasted the output of argocd version.

Describe the bug

ArgoCD's server-side apply implementation cannot remove fields that were previously applied by client-side apply (kubectl apply) or other field managers. When migrating from client-side apply to server-side apply, removed fields remain in the resource indefinitely, even when they are no longer present in the desired manifest. This leads to resources that are inconsistent with their expected state.

The root cause is that server-side apply only manages fields that are explicitly specified in the applied manifest. Fields owned by other field managers (like kubectl with Update operation) persist even when they should be removed, because ArgoCD's field manager cannot take ownership of fields it doesn't explicitly apply.

This is the same issue described in https://github.com/kubernetes/kubernetes/issues/99003

As the upstream issue has still been open for awhile and doesn't look like it will be resolved soon, we should implement a workaround solution for this case as this will be a common case if users applied resources using kubectl apply before managing with argocd. Or if users have other legacy controllers managing fields that they want to later remove.

To Reproduce

  1. Apply a manifest using client-side apply (kubectl apply):
cat <<EOF | kubectl -n default apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-config
data:
  key1: value1
  key2: value2
  legacy_field: should_be_removed
EOF
  1. Configure ArgoCD to manage this resource with server-side apply enabled. i.e add this file to Git and create an app that manages this file.
  2. Sync without ServerSideApply
  3. Observe in managed fields in argoCD. Since we applied using kubectl apply -f, the fields are owned by `manager: kubectl-client-side-apply
  managedFields:
    - apiVersion: v1
      fieldsType: FieldsV1
      fieldsV1:
        f:data:
          .: {}
          f:key1: {}
          f:key2: {}
          f:legacy_field: {}
        f:metadata:
          f:annotations: {}
      manager: kubectl-client-side-apply
      operation: Update
      time: '2025-05-30T20:29:26Z'
    - apiVersion: v1
      fieldsType: FieldsV1
      fieldsV1:
        f:metadata:
          f:annotations:
            f:argocd.argoproj.io/tracking-id: {}
            f:kubectl.kubernetes.io/last-applied-configuration: {}
      manager: argocd-controller
      operation: Update
      time: '2025-05-30T20:30:09Z'
  1. Remove the field in Git
kind: ConfigMap
metadata:
  name: test-config
data:
  key1: value1
  key2: value2
  # legacy_field removed
  1. Sync with ServerSideApply
  2. Observe that the legacy_field still exists in the cluster:
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-config
data:
  key1: value1
  key2: value2
  legacy_field: should_be_removed

Expected behavior

Field should be removed from live manifest after sync with ServerSideApply

Screenshots

Version

argocd version
argocd: v2.14.9+38985bd.dirty
  BuildDate: 2025-04-02T23:02:54Z
  GitCommit: 38985bdcd6c3b031fb83757a1fb0c39a55bf6a24
  GitTreeState: dirty
  GoVersion: go1.24.2
  Compiler: gc
  Platform: darwin/amd64
argocd-server: v3.0.3+c27a9d3.dirty
  BuildDate: 2025-05-27T23:39:57Z
  GitCommit: c27a9d33603b399b228d896e98d4a5fc86afd53c
  GitTreeState: dirty
  GoVersion: go1.24.3
  Compiler: gc
  Platform: darwin/amd64
  Kustomize Version: v5.4.3 2024-07-19T16:40:33Z
  Helm Version: v3.17.1+g980d8ac
  Kubectl Version: v0.32.2
  Jsonnet Version: v0.20.0

Logs

Paste any relevant application logs here.

pjiang-dev avatar May 30 '25 20:05 pjiang-dev

FluxCD has run into this issue and fixed it by adding a 'Cleanup' applyOption that manipulates the managed fields and replaces problematic managers like kubectl- with their own manager https://github.com/fluxcd/kustomize-controller/pull/527

We could do something similar and add a cleanup option in conjunction with ServerSideApply to clean up managed fields before applying.

pjiang-dev avatar May 30 '25 20:05 pjiang-dev

Similar to #22797

Would've been nice to have something this upstream (kubernetes/kubernetes#124191), but since that's not coming anytime soon I agree it should be implemented in Argo CD instead

blakepettersson avatar May 31 '25 12:05 blakepettersson