Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add TransformStripManagedFields #2791

Merged

Conversation

alvaroaleman
Copy link
Member

@alvaroaleman alvaroaleman commented Apr 21, 2024

This change adds TransformStripManagedFields to the Cache, a transform func that strips off all managed fields for objects. There are no known issues when using this as a DefaultTransform unless there is explicit code to access objects ManagedFields and it can lead to a significant reduction in memory usage.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Apr 21, 2024
@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Apr 21, 2024
@alvaroaleman alvaroaleman force-pushed the add-default-transform branch from 01dce5f to 742fa6c Compare April 21, 2024 12:02
@alvaroaleman alvaroaleman changed the title :sparkling: Add TransformStripManagedFields ✨ Add TransformStripManagedFields Apr 21, 2024
@alvaroaleman alvaroaleman force-pushed the add-default-transform branch 2 times, most recently from a7015d9 to 85aa0fc Compare April 21, 2024 15:16
This change adds `TransformStripManagedFields` to the Cache, a
transform func that strips off all managed fields for objects. There are
no known issues when using this as a `DefaultTransform` unless there is
explicit code to access objects `ManagedFields` and can lead to a
significant reduction in memory usage.
@alvaroaleman alvaroaleman force-pushed the add-default-transform branch from 85aa0fc to 4cf9db0 Compare April 21, 2024 15:24
Copy link
Member

@Danil-Grigorev Danil-Grigorev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very useful when using client.Patch with Apply logic, thanks
/lgtm
/hold
if anyone wants to take a look

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 21, 2024
@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Apr 21, 2024
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: 8bfda55969144726bdabcfb9c7cad9a597b588a0

@sbueringer
Copy link
Member

Thx!!

/approve
/lgtm

/hold cancel

@k8s-ci-robot k8s-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 22, 2024
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: alvaroaleman, Danil-Grigorev, sbueringer

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:
  • OWNERS [alvaroaleman,sbueringer]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot merged commit 5823d1b into kubernetes-sigs:main Apr 22, 2024
9 checks passed
akutz added a commit to akutz/vm-operator that referenced this pull request Sep 11, 2024
This patch adds support for stripping managed fields for objects
entering the cache. The controller-runtime documentation for this
transformer states:

    If you are not explicitly accessing managedFields from your code,
    setting this as `DefaultTransform` on the cache can lead to
    significant reduction in memory usage.

Given that VM Operator never directly accesses the managed fields
for any object, there is no reason we should not be using this
transformer.

Please see
kubernetes-sigs/controller-runtime#2791
for more information on this feature.
akutz added a commit to akutz/vm-operator that referenced this pull request Sep 11, 2024
This patch adds support for stripping managed fields for objects
entering the cache. The controller-runtime documentation for this
transformer states:

    If you are not explicitly accessing managedFields from your code,
    setting this as `DefaultTransform` on the cache can lead to
    significant reduction in memory usage.

Given that VM Operator never directly accesses the managed fields
for any object, there is no reason we should not be using this
transformer.

Please see
kubernetes-sigs/controller-runtime#2791
for more information on this feature.
@akutz
Copy link
Contributor

akutz commented Sep 11, 2024

Howdy @alvaroaleman,

How did you arrive at:

There are no known issues when using this as a DefaultTransform unless there is explicit code to access objects ManagedFields

Per https://kubernetes.io/docs/reference/using-api/server-side-apply/:

It is however possible to change .metadata.managedFields through an update, or through a patch operation that does not use Server-Side Apply. Doing so is highly discouraged, but might be a reasonable option to try if, for example, the .metadata.managedFields get into an inconsistent state (which should not happen in normal operations).

Is the transformer from this PR not going to result in controllers sending patches/updates that no longer have the managed fields? For example, none of our controllers directly access managed fields, but we do write objects back to etcd, and if the cached object no longer has the managed fields, won't an update (we do use patch, but for example) remove the managed fields?

Is it because an update from a controller-runtime manager client will have field manager ID of manager (by default) and thus not impact the managed fields of another field manager, like the client kubectl, which uses the field manager ID of kubectl?

@sbueringer
Copy link
Member

sbueringer commented Sep 11, 2024

I think with patch, if you don't modify the managed fields in your code they simply won't be part of the delta and thus not part of the patch sent to the apiserver (so doesn't matter if they are there and don't have a diff or if they are not there and don't have a diff).

It is definitely easily possible to Patch managedFields if you actually modify managed fields in your code. We're using this in some places in Cluster API.

I have no experience with update. There I could imagine it might lead to problems

akutz added a commit to akutz/vm-operator that referenced this pull request Sep 11, 2024
This patch adds support for stripping managed fields for objects
entering the cache. The controller-runtime documentation for this
transformer states:

    If you are not explicitly accessing managedFields from your code,
    setting this as `DefaultTransform` on the cache can lead to
    significant reduction in memory usage.

Given that VM Operator never directly accesses the managed fields
for any object, there is no reason we should not be using this
transformer.

Please see
kubernetes-sigs/controller-runtime#2791
for more information on this feature.
akutz added a commit to akutz/vm-operator that referenced this pull request Sep 11, 2024
This patch adds support for stripping managed fields for objects
entering the cache. The controller-runtime documentation for this
transformer states:

    If you are not explicitly accessing managedFields from your code,
    setting this as `DefaultTransform` on the cache can lead to
    significant reduction in memory usage.

Given that VM Operator never directly accesses the managed fields
for any object, there is no reason we should not be using this
transformer.

Please see
kubernetes-sigs/controller-runtime#2791
for more information on this feature.
@akutz
Copy link
Contributor

akutz commented Sep 11, 2024

I think with patch, if you don't modify the managed fields in your code they simply won't be part of the delta and thus not part of the patch sent to the apiserver (so doesn't matter if they are there and don't have a diff or if they are not there and don't have a diff).

It is definitely easily possible to Patch managedFields if you actually modify managed fields in your code. We're using this in some places in Cluster API.

I have no experience with update. There I could imagine it might lead to problems

If the above is true, then I do think the documentation for the transformer and description of this PR should be updated. Otherwise the current documentation makes it sound like there is zero downside for using the stripping transformer, but that may not be the case if folks are using client.Update or controllerutil.CreateOrUpdate with a caching client that strips managed fields.

@sbueringer
Copy link
Member

sbueringer commented Sep 11, 2024

Let's see if someone else knows more. I simply never tried what happens with Update, we are always using Patch

@alvaroaleman
Copy link
Member Author

So a quick test shows that update with nil managed fields does not clear them:

k get deployment coredns -ojson --show-managed-fields=true|jq .metadata.managedFields >/tmp/original
cat main.go
package main

import (
	"context"

	appsv1 "k8s.io/api/apps/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

func main() {
	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Cache: cache.Options{DefaultTransform: cache.TransformStripManagedFields()},
	})
	if err != nil {
		panic(err)
	}

	go func() {
		if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
			panic(err)
		}
	}()

	ctx := context.Background()
	if _, err := mgr.GetCache().GetInformer(ctx, &appsv1.Deployment{}); err != nil {
		panic(err)
	}
	dep := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{
		Name:      "coredns",
		Namespace: "kube-system",
	}}
	if err := mgr.GetClient().Get(ctx, client.ObjectKeyFromObject(dep), dep); err != nil {
		panic(err)
	}

	dep.Annotations["foo"] = "bar"
	if err := mgr.GetClient().Update(ctx, dep); err != nil {
		panic(err)
	}
}

go run ./
k get deployment coredns -ojson --show-managed-fields=true|jq .metadata.managedFields >/tmp/updated
$ diff -u /tmp/original /tmp/updated
--- /tmp/original	2024-09-11 21:42:10
+++ /tmp/updated	2024-09-11 21:44:14
@@ -164,6 +164,20 @@
     "fieldsV1": {
       "f:metadata": {
         "f:annotations": {
+          "f:foo": {}
+        }
+      }
+    },
+    "manager": "foo.bar",
+    "operation": "Update",
+    "time": "2024-09-12T01:44:07Z"
+  },
+  {
+    "apiVersion": "apps/v1",
+    "fieldsType": "FieldsV1",
+    "fieldsV1": {
+      "f:metadata": {
+        "f:annotations": {
           ".": {},
           "f:deployment.kubernetes.io/revision": {}
         }
@@ -200,6 +214,6 @@
     "manager": "kube-controller-manager",
     "operation": "Update",
     "subresource": "status",
-    "time": "2024-08-31T22:23:53Z"
+    "time": "2024-09-12T01:44:07Z"
   }
 ]

It should also be mentioned that upstream did this change for the controller-manager and scheduler), those two are what prompted me to do this change.

According to that scheduler PR even if scheduler use Update method on Pod in the future, updating Pod with managedFields being nil has no impact as kube-apiserver calculates the managed fields from the live object so I do think this is safe.

@alvaroaleman alvaroaleman deleted the add-default-transform branch September 12, 2024 01:54
@sbueringer
Copy link
Member

sbueringer commented Sep 12, 2024

Nice! Thx for testing! So there is special handling for nil. I assume if some managedfields are set/modified it would update accordingly
(As mentioned in Cluster API we are using only patch, with patch we were able to modify managed fields)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants