-
Notifications
You must be signed in to change notification settings - Fork 17
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
EVEREST-1654 Use controller-runtime client instead of Rest #1132
base: main
Are you sure you want to change the base?
Conversation
@@ -82,34 +83,49 @@ func (k *Kubernetes) IsBackupStorageUsed(ctx context.Context, namespace, name st | |||
} | |||
|
|||
// Check if it is in use by clusters? | |||
clusters, err := k.client.ListDatabaseClusters(ctx, namespace, metav1.ListOptions{}) | |||
if err != nil { | |||
listOpts := &ctrlclient.ListOptions{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is an example of FieldSelector usage over .spec.backup.schedules.backupStorageName
in DatabaseCluster CR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file is not needed any more since all logic is placed in pkg/kubernetes/database_cluster.go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file is not needed any more since all logic is placed in pkg/kubernetes/database_cluster.go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once all logic is moved to pkg/kubernetes/
- this file can be removed as well
@@ -29,27 +30,39 @@ import ( | |||
|
|||
// ListDatabaseClusters returns list of managed database clusters. | |||
func (k *Kubernetes) ListDatabaseClusters(ctx context.Context, namespace string) (*everestv1alpha1.DatabaseClusterList, error) { | |||
return k.client.ListDatabaseClusters(ctx, namespace, metav1.ListOptions{}) | |||
result := &everestv1alpha1.DatabaseClusterList{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is an example of the logic that replaces one from pkg/kubernetes/client/
+ pkg/kubernetes/client/customresources
layers
} | ||
|
||
// GetDatabaseCluster returns database clusters by provided name. | ||
func (k *Kubernetes) GetDatabaseCluster(ctx context.Context, namespace, name string) (*everestv1alpha1.DatabaseCluster, error) { | ||
return k.client.GetDatabaseCluster(ctx, namespace, name) | ||
result := &everestv1alpha1.DatabaseCluster{} | ||
err := k.k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k.k8sClient.Get
and k.k8sClient.List
operations use cache that is being updated in background and in case resource in K8S is changed
@@ -90,7 +93,10 @@ var ErrEmptyVersionTag = errors.New("got an empty version tag from Github") | |||
|
|||
// Kubernetes is a client for Kubernetes. | |||
type Kubernetes struct { | |||
client client.KubeClientConnector | |||
// client client.KubeClientConnector | |||
client *client.Client |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this client
will be removed once all logic from pkg/kubernetes/client/
+ pkg/kubernetes/client/customresources
layers is moved to pkg/kubernetes/
layer
// initIndexers initializes the field indexers for the DatabaseCluster. | ||
func (k *Kubernetes) initIndexers(ctx context.Context) error { | ||
if err := k.k8sCache.IndexField( | ||
ctx, &everestv1alpha1.DatabaseCluster{}, ".spec.backup.schedules.backupStorageName", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is an example of indexing field in .spec
for our DatabaseCluster CR. This index is later used for DBs lookup by field
Hi @maxkondr in general I like this idea but I also have a few questions/concerns. First of all, besides the
Here are the concerns that came through my mind that might merit some discussion:
Here's an interesting read that, among other things, discusses the differences from the client-go and controller-runtime clients and cache mechanisms. Even though, the author approaches it from the point of view of a controller/operator we can still use this info to make a more informed decision about what to use in our API server. |
controller-runtime's client and cache need kubeconfig to initialise outside of K8S. Once we decide to implement multi-K8S support we anyway need kubeconfigs to access external clusters, so there are no issues with this.
Well, first of all most of currently used client sets are generated and we utilise them as external dependency so that we statically tie up with them and they can be replaced by generic controller-runtime client does not rely on generated clientsets. Internally, it still relies on client-go primitives, but we don’t need to setup code generation in order to use it for custom resources. Instead, a single controller-runtime client can be used for managing all Kubernetes resources (built-in and extended) homogeneously.
But at the same time, our current server implementation creates load on K8S API. Regarding caching resources.
And one more point that worth to be outlined. The cache may contain slightly out-of-date state of the object (due to some lag between object updated in K8S API and object update in cache). So that we have some chance that we present to user on UI/API not "the latest" state of object. But we have a remediation mechanisms for this:
I think we shall start to cache only our CRs (DatabaseCluster, DatabaseClusterBackup, etc) since there won't be a huge number of them in K8S (in comparing to Secrets,Pods, etc). So it provides us with certain flexibility by the cost of an additional memory consumption. Yep, good article, thanks |
Thanks @maxkondr for the follow-up on this discussion. I agree with you and I think it's probably worth going ahead with implementing your proposal but before you jump to a full implementation let's hear from @mayankshah1607. |
In general I also like the idea of using the But I have concerns about the caching:
tl;dr - controller-runtime.Client is good, but I am not convinced we need caching. Yes, our current implementation makes direct API calls but I would not try to optimise without knowing how much to optimise for, especially considering the added complexity. Maybe we should at least provide an option to disable client cache |
@mayankshah1607 thanks for your comments. In such a case, I would suggest the following:
@mayankshah1607 , @recharte - comments/objections? |
Yes, that sounds good. 👍🏻 |
This is a PoC.
The idea is the following:
pkg/kubernetes/client/
andpkg/kubernetes/client/customresources
) can be removed. Instead, the logic can be placed inpkg/kubernetes.Kubernetes
.controller-runtime.Client
with cache is used inpkg/kubernetes.Kubernetes
in the same way it is used in Everest-operator.-- this allows us to remove the logic in
everest-operator
that copies values from.spec.
fields tometadata.labels
for our CRs.