-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
What is the proper way to compare resource object? #592
Comments
/triage support |
Thanks for your reply. I did some further tests. It is like what you said the Deployment.Status was kept being updated. |
Just don't take any action. |
I have run into this issue as well. I think doing
Maybe it’d be better if the scaffolding only compared for changes for things that the controller should take action on or are part of the CRD abstraction e.g. the |
It also bothered me that too many unnecessary updates were done because of the DeepEqual, so I implemented this approach:
This way, I don't need to do a deep-compare each time the reconcile function is triggered, and I also push less changes to kubernetes. |
https://github.com/banzaicloud/k8s-objectmatcher might be a possible solution to this? |
Server-side apply is the ultimate solution, when it eventually lands as beta. |
@DirectXMan12 will the server-side apply solution work without contacting the API server? Isn't a dry-run call against the API necessary in that case as well? |
Ideally (for example with https://github.com/banzaicloud/k8s-objectmatcher and controller-runtime of course) we get some (or most) of our managed objects from the cache and we can decide whether there are any changes or not locally. I understand server-side apply is more elegant, but if it involves a call to the API server then it's not exactly a solution to the above problem. |
@pepov with server-side apply, you do need to contact the api server, but you don't need to compare objects. Instead, you explicitly set all the fields you care about on an empty object (not one you've gotten from the cache) and then submit that to the API server. The API server takes care of figuring out the difference. That means that you always submit against the API server, but that the submission doesn't always change things, without having to care about local comparison. |
(whoops, didn't mean to close) |
@DirectXMan12 the issue in our case was that we hit the API server too hard with too much requests, also the overall time for an operator cycle increased because of this. |
In this case, when should we make the submit? If we make the submit in every reconciliation, will that cause too much load for api server in worst case? |
@ChenDoRo ideally, no, it should not cause too much load, but it depends on your usecase. It's in alpha now, and will most likely be beta in the next kubernetes release @pepov was it actually a server-side issue? You can also hit client-side rate limiting pretty easy with the default values. At any rate, I'd be curious to see your numbers on that. |
Issues go stale after 90d of inactivity. If this issue is safe to close now please do so with Send feedback to sig-testing, kubernetes/test-infra and/or fejta. |
Maybe late to the party but I raised this in kubernetes and they pointed me at kubernetes/apimachinery#75
|
this still won't work in some cases, like when the default for a field is not its zero-value. I end up doing the same thing @schweikert recommended. |
Stale issues rot after 30d of inactivity. If this issue is safe to close now please do so with Send feedback to sig-testing, kubernetes/test-infra and/or fejta. |
Rotten issues close after 30d of inactivity. Send feedback to sig-testing, kubernetes/test-infra and/or fejta. |
@fejta-bot: Closing this issue. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
I also have the problem using reflect.DeepEqual or equality.Semantic.DeepEqual because some fields are set with default non-zero values by some controller (like ImagePullPolicy, RestartPolicy, and so on) if these fields are not set by the operator. I found this utility function that makes the job for me: it compares only fields that are non-zero in the expected struct: import "k8s.io/apimachinery/pkg/api/equality"
if !equality.Semantic.DeepDerivative(expected.Spec, found.Spec) {
// some field set by the operator has changed
} |
It will ignore some update, maybe I'm trying to add a field to deployment(or delete some fields of it), but it will ignore it |
Same here, |
This works very well, but can avoid having one more dependency by using
|
k8s sets fields when we submit our CRD to the api, this causes issues when we come to compare local versions to it later. kubernetes-sigs/kubebuilder#592
* Loosen equality on crds. k8s sets fields when we submit our CRD to the api, this causes issues when we come to compare local versions to it later. kubernetes-sigs/kubebuilder#592 * Remove redundant check * Remove redundant word * Address comments
One thing to be mindful about this approach is it doesn't eliminate configuration drift that originates outside the controller in-question. If someone updates the controlled object state, say using kubectl, in a way that the desired state is out of sync with the actual state, the generated hash still won't differ and the controller won't revert that change (until the reconciliation happens to produce a different result from its last update). This is often not how controllers are meant to behave. The controllerutil lib uses the |
I also encountered a similar problem. The solution is to update first, and use the client.DryRunAll parameter option, and then use reflect.DeepEqual to compare Spec to achieve the goal. Code reference
It‘s work now |
In the generated code, reflect.DeepEqual is used to check if the resource is changed. I created a deployment then used reflect.DeepEqual to compare it with the one fetched from k8s. The issue is the one fetched from k8s was changed by deployment controller (I assume it is) by filling with default values and is different from the deployment I constructed. This will trigger a update to deployment. And it seems this will happen continuously. Is this something expected? Or I am missing something?
Thanks.
The text was updated successfully, but these errors were encountered: