最大化CustomResourceDefinition可以拥有的CustomResources数量 | kubebuilder和operator-sdk

huangapple go评论159阅读模式
英文:

Maximize the number of CustomResources that a CustomResourceDefinition can have | kubebuilder & operator-sdk

问题

我正在开发一个 Kubernetes Operator,它代表了一个非常简单的 API 和一个控制器。
我想要最大化属于操作员定义的特定 CustomResourceDefinition 的 CustomResources 的数量。(特别是,如果已经定义了一个 CR,操作员应该抛出一个错误消息并跳过对其进行调和。)
如果我生成了 API,会默认生成一个 KindList 结构体,并且如果我理解正确的话,它应该跟踪已为我的 CRD 定义的 CR。它也会默认添加到 scheme 中。请参考 kubebuilder 文档中的示例:

  1. //+kubebuilder:object:root=true
  2. //+kubebuilder:subresource:status
  3. // CronJob is the Schema for the cronjobs API
  4. type CronJob struct {
  5. metav1.TypeMeta `json:",inline"`
  6. metav1.ObjectMeta `json:"metadata,omitempty"`
  7. Spec CronJobSpec `json:"spec,omitempty"`
  8. Status CronJobStatus `json:"status,omitempty"`
  9. }
  10. //+kubebuilder:object:root=true
  11. // CronJobList contains a list of CronJob
  12. type CronJobList struct {
  13. metav1.TypeMeta `json:",inline"`
  14. metav1.ListMeta `json:"metadata,omitempty"`
  15. Items []CronJob `json:"items"`
  16. }
  17. func init() {
  18. SchemeBuilder.Register(&CronJob{}, &CronJobList{})
  19. }

不幸的是,我找不到如何从控制器中访问这个 List。我尝试过这样,但是 r.Get 无法接受 cacheList:

  1. cronjob/cronjob_controller.go
  2. package controllers
  3. import (
  4. "context"
  5. "k8s.io/apimachinery/pkg/runtime"
  6. ctrl "sigs.k8s.io/controller-runtime"
  7. "sigs.k8s.io/controller-runtime/pkg/client"
  8. "sigs.k8s.io/controller-runtime/pkg/log"
  9. cronjobv1alpha1 "github.com/example/cronjob-operator/api/v1alpha1"
  10. )
  11. func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  12. _ = log.FromContext(ctx)
  13. // TODO(user): your logic here
  14. cronjob := cronjobv1alpha1.Memcached{}
  15. if err := r.Get(ctx, req.NamespacedName, &cronjob); err != nil {
  16. return ctrl.Result{}, err
  17. }
  18. cronjobList := cachev1alpha1.MemcachedList{}
  19. if err := r.Get(ctx, req.NamespacedName, &cronjobList); err != nil {
  20. return ctrl.Result{}, err
  21. }
  22. return ctrl.Result{}, nil
  23. }

如果我获取了这个列表,我可以验证它的长度,并根据需要执行或跳过调和。

这种方法是否正确?是否有更好的方法来实现我的目标?我应该创建一个 webhook 吗?

英文:

I'm developing a kubernetes operator that represents a very simple api and a controller.
I would like to maximize the number of the CustomResources those could belonging to the specific CustomResourceDefinition that the operator defines. (As specially I would like to allow just one CR, if it is already defined, the operator should throw an error message and skip reconciling it.)
If I generate the api, there is a KindList struct default generated, and if I understand correctly, it should keep track of the CRs already defined for my CRD. It is also added to the scheme by default. See the example from kubebuilder documentation:

  1. //+kubebuilder:object:root=true
  2. //+kubebuilder:subresource:status
  3. // CronJob is the Schema for the cronjobs API
  4. type CronJob struct {
  5. metav1.TypeMeta `json:",inline"`
  6. metav1.ObjectMeta `json:"metadata,omitempty"`
  7. Spec CronJobSpec `json:"spec,omitempty"`
  8. Status CronJobStatus `json:"status,omitempty"`
  9. }
  10. //+kubebuilder:object:root=true
  11. // CronJobList contains a list of CronJob
  12. type CronJobList struct {
  13. metav1.TypeMeta `json:",inline"`
  14. metav1.ListMeta `json:"metadata,omitempty"`
  15. Items []CronJob `json:"items"`
  16. }
  17. func init() {
  18. SchemeBuilder.Register(&CronJob{}, &CronJobList{})
  19. }

Unfortunately, I can not find out how to access this List from the controller. I have tried like this, but r.Get can not accept cacheList:

  1. cronjob/cronjob_controller.go
  2. package controllers
  3. import (
  4. "context"
  5. "k8s.io/apimachinery/pkg/runtime"
  6. ctrl "sigs.k8s.io/controller-runtime"
  7. "sigs.k8s.io/controller-runtime/pkg/client"
  8. "sigs.k8s.io/controller-runtime/pkg/log"
  9. cronjobv1alpha1 "github.com/example/cronjob-operator/api/v1alpha1"
  10. )
  11. func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  12. _ = log.FromContext(ctx)
  13. // TODO(user): your logic here
  14. cronjob := cronjobv1alpha1.Memcached{}
  15. if err := r.Get(ctx, req.NamespacedName, &cronjob); err != nil {
  16. return ctrl.Result{}, err
  17. }
  18. cronjobList := cachev1alpha1.MemcachedList{}
  19. if err := r.Get(ctx, req.NamespacedName, &cronjobList); err != nil {
  20. return ctrl.Result{}, err
  21. }
  22. return ctrl.Result{}, nil
  23. }

If I get the list, I could validate the length of it, and do or skip the reconcile.

Is it even a correct approach? Is there a better way to achieve my goal? Should I create a webhook instead?

答案1

得分: 2

假设您正在使用默认的sigs.k8s.io/controller-runtime/pkg/clientclient.Client,您可以访问List()函数。

在您的情况下,使用r.List(...)

用法如下:

情况1:按标签列出

  1. func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  2. cronjobList := cronjobv1alpha1.CronJobList{}
  3. err = r.List(ctx, &cronjobList, client.MatchingLabels{"foo": "bar"})
  4. if err != nil {
  5. return ctrl.Result{}, err
  6. }
  7. }

情况2:列出命名空间中的所有对象

  1. func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  2. cronjobList := cronjobv1alpha1.CronJobList{}
  3. err = r.List(ctx, &cronjobList, client.InNamespace("default"))
  4. if err != nil {
  5. return ctrl.Result{}, err
  6. }
  7. }

情况3:按字段(例如metadata.name)列出

  1. // 在您的Reconciler Setup函数中创建一个索引
  2. func SetupWithManager(mgr ctrl.Manager) error {
  3. r := &CronJobReconciler{
  4. Client: mgr.GetClient(),
  5. }
  6. mgr.GetFieldIndexer().IndexField(context.TODO(), &cronjobv1alpha1.CronJob{}, "metadata.name", NameIndexer)
  7. return ctrl.NewControllerManagedBy(mgr).
  8. For(&cronjobv1alpha1.CronJob{}).
  9. Complete(r)
  10. }
  11. func NameIndexer(o client.Object) []string {
  12. m := o.(*cronjobv1alpha1.CronJob)
  13. return []string{m.ObjectMeta.Name}
  14. }
  15. func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  16. cronjobList := cronjobv1alpha1.CronJobList{}
  17. err = r.List(ctx, &cronjobList, client.MatchingFields{"metadata.name": "test"})
  18. if err != nil {
  19. return ctrl.Result{}, err
  20. }
  21. }
英文:

Assuming you are using the default sigs.k8s.io/controller-runtime/pkg/client's client.Client, you get access to the List() function.

In your case r.List(...).

Usage:

case 1: list by label

  1. func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  2. cronjobList := cronjobv1alpha1.CronJobList{}
  3. err = r.List(ctx, &cronjobList, client.MatchingLabels{"foo": "bar"})
  4. if err != nil {
  5. return ctrl.Result{}, err
  6. }
  7. }

case 2: list all in namespace

  1. func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  2. cronjobList := cronjobv1alpha1.CronJobList{}
  3. err = r.List(ctx, &cronjobList, client.InNamespace("default"))
  4. if err != nil {
  5. return ctrl.Result{}, err
  6. }
  7. }

case 3: list by field i.e. metadata.name

  1. // in your Reconciler Setup function create an index
  2. func SetupWithManager(mgr ctrl.Manager) error {
  3. r := &CronJobReconciler{
  4. Client: mgr.GetClient(),
  5. }
  6. mgr.GetFieldIndexer().IndexField(context.TODO(), &cronjobv1alpha1.CronJob{}, "metadata.name", NameIndexer)
  7. return ctrl.NewControllerManagedBy(mgr).
  8. For(&cronjobv1alpha1.CronJob{}).
  9. Complete(r)
  10. }
  11. func NameIndexer(o client.Object) []string {
  12. m := o.(*cronjobv1alpha1.CronJob)
  13. return []string{m.ObjectMeta.Name}
  14. }
  15. func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  16. cronjobList := cronjobv1alpha1.CronJobList{}
  17. err = r.List(ctx, &cronjobList, client.MatchingFields{"metadata.name": "test"})
  18. if err != nil {
  19. return ctrl.Result{}, err
  20. }
  21. }

huangapple
  • 本文由 发表于 2022年10月21日 03:11:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/74145169.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定