日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
一篇帶你kubebuilder實(shí)戰(zhàn):status&event

在上篇文章當(dāng)中我們實(shí)現(xiàn)了 NodePool Operator 基本的 CURD 功能,跑了一小段時(shí)間之后除了 CURD 之外我們有了更高的需求,想知道一個(gè)節(jié)點(diǎn)池有多少的節(jié)點(diǎn),現(xiàn)在的資源占比是多少,這樣可以清晰的知道我們現(xiàn)在的水位線是多少,除此之外也想知道節(jié)點(diǎn)池?cái)?shù)量發(fā)生變化的相關(guān)事件信息,什么時(shí)候節(jié)點(diǎn)池增加或者是減少了一個(gè)節(jié)點(diǎn)等。

需求

我們先整理一下需求

能夠通過(guò) kubectl get Nodepool了解當(dāng)前的節(jié)點(diǎn)池的以下信息

  • 節(jié)點(diǎn)池的狀態(tài),是否異常
  • 節(jié)點(diǎn)池現(xiàn)在包含多少個(gè)節(jié)點(diǎn)
  • 節(jié)點(diǎn)池的資源情況現(xiàn)在有多少 CPU、Memory

能夠通過(guò)事件信息得知 controller 的錯(cuò)誤情況以及節(jié)點(diǎn)池內(nèi)節(jié)點(diǎn)的變化情況

實(shí)現(xiàn)

Status

先修改一下 status 對(duì)象,注意要確保下面的 //+kubebuilder:subresource:status注釋存在,這個(gè)表示開(kāi)啟 status 子資源,status 對(duì)象修改好之后需要重新執(zhí)行一遍 make install

 
 
 
 
  1. // NodePoolStatus defines the observed state of NodePool
  2. type NodePoolStatus struct {
  3.  // status=200 說(shuō)明正常,其他情況為異常情況
  4.  Status int `json:"status"`
  5.  // 節(jié)點(diǎn)的數(shù)量
  6.  NodeCount int `json:"nodeCount"`
  7.  // 允許被調(diào)度的容量
  8.  Allocatable corev1.ResourceList `json:"allocatable,omitempty" protobuf:"bytes,2,rep,name=allocatable,casttype=ResourceList,castkey=ResourceName"`
  9. }
  10. //+kubebuilder:object:root=true
  11. //+kubebuilder:resource:scope=Cluster
  12. //+kubebuilder:subresource:status
  13. // NodePool is the Schema for the nodepools API
  14. type NodePool struct {

然后修改 Reconcile 中的邏輯

 
 
 
 
  1. func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  2.  // ......
  3.  if len(nodes.Items) > 0 {
  4.   r.Log.Info("find nodes, will merge data", "nodes", len(nodes.Items))
  5. +  pool.Status.Allocatable = corev1.ResourceList{}
  6. +  pool.Status.NodeCount = len(nodes.Items)
  7.   for _, n := range nodes.Items {
  8.    n := n
  9.    // 更新節(jié)點(diǎn)的標(biāo)簽和污點(diǎn)信息
  10.    err := r.Update(ctx, pool.Spec.ApplyNode(n))
  11.    if err != nil {
  12.     return ctrl.Result{}, err
  13.    }
  14. +   for name, quantity := range n.Status.Allocatable {
  15. +    q, ok := pool.Status.Allocatable[name]
  16. +    if ok {
  17. +     q.Add(quantity)
  18. +     pool.Status.Allocatable[name] = q
  19. +     continue
  20. +    }
  21. +    pool.Status.Allocatable[name] = quantity
  22. +   }
  23.   }
  24.  }
  25.   // ......
  26.   
  27. + pool.Status.Status = 200
  28. + err = r.Status().Update(ctx, pool)
  29.  return ctrl.Result{}, err
  30. }

修改好了之后我們提交一個(gè) NodePool 測(cè)試一下

 
 
 
 
  1. apiVersion: nodes.lailin.xyz/v1
  2. kind: NodePool
  3. metadata:
  4.   name: worker
  5. spec:
  6.   taints:
  7.     - key: node-pool.lailin.xyz
  8.       value: worker
  9.       effect: NoSchedule
  10.   labels:
  11.     "node-pool.lailin.xyz/worker": "10"
  12.   handler: runc

可以看到我們現(xiàn)在是有兩個(gè) worker 節(jié)點(diǎn)

 
 
 
 
  1. ? kubectl get no 
  2. NAME                 STATUS   ROLES                  AGE   VERSION
  3. kind-control-plane   Ready    control-plane,master   29m   v1.20.2
  4. kind-worker          Ready    worker                 28m   v1.20.2
  5. kind-worker2         Ready    worker                 28m   v1.20.2

 然后我們看看 NodePool,可以發(fā)現(xiàn)已經(jīng)存在了預(yù)期的 status

 
 
 
 
  1. status:
  2.   allocatable:
  3.     cpu: "8"
  4.     ephemeral-storage: 184026512Ki
  5.     hugepages-1Gi: "0"
  6.     hugepages-2Mi: "0"
  7.     memory: 6129040Ki
  8.     pods: "220"
  9.   nodeCount: 2
  10.   status: 200

現(xiàn)在這樣只能通過(guò)查看 yaml 詳情才能看到,當(dāng) NodePool 稍微多一些的時(shí)候就不太方便,我們現(xiàn)在給NodePool 增加一些 kubectl 展示的列

 
 
 
 
  1. +//+kubebuilder:printcolumn:JSONPath=".status.status",name=Status,type=integer
  2. +//+kubebuilder:printcolumn:JSONPath=".status.nodeCount",name=NodeCount,type=integer
  3. //+kubebuilder:object:root=true
  4. //+kubebuilder:resource:scope=Cluster
  5. //+kubebuilder:subresource:status

如上所示只需要添加好對(duì)應(yīng)的注釋?zhuān)缓髨?zhí)行 make install即可

然后再執(zhí)行 kubectl get NodePool 就可以看到對(duì)應(yīng)的列了

 
 
 
 
  1. ? kubectl get NodePool 
  2. NAME     STATUS   NODECOUNT
  3. worker   200      2

Event

我們?cè)?controller 當(dāng)中添加 Recorder 用來(lái)記錄事件,K8s 中事件有 Normal 和 Warning 兩種類(lèi)型

 
 
 
 
  1. // NodePoolReconciler reconciles a NodePool object
  2. type NodePoolReconciler struct {
  3.  client.Client
  4.  Log      logr.Logger
  5.  Scheme   *runtime.Scheme
  6. + Recorder record.EventRecorder
  7. }
  8. func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  9.  
  10. + // 添加測(cè)試事件
  11. + r.Recorder.Event(pool, corev1.EventTypeNormal, "test", "test")
  12.  pool.Status.Status = 200
  13.  err = r.Status().Update(ctx, pool)
  14.  return ctrl.Result{}, err
  15. }

添加好之后還需要在 main.go 中加上 Recorder的初始化邏輯

 
 
 
 
  1. if err = (&controllers.NodePoolReconciler{
  2.   Client:   mgr.GetClient(),
  3.   Log:      ctrl.Log.WithName("controllers").WithName("NodePool"),
  4.   Scheme:   mgr.GetScheme(),
  5. +  Recorder: mgr.GetEventRecorderFor("NodePool"),
  6.  }).SetupWithManager(mgr); err != nil {
  7.   setupLog.Error(err, "unable to create controller", "controller", "NodePool")
  8.   os.Exit(1)
  9.  }

加好之后我們運(yùn)行一下,然后在 describe Nodepool 對(duì)象就能看到事件信息了

 
 
 
 
  1. Events:
  2.   Type    Reason  Age   From      Message
  3.   ----    ------  ----  ----      -------
  4.   Normal  test    4s    NodePool  test

監(jiān)聽(tīng)更多資源

之前我們所有的代碼都是圍繞著 NodePool 的變化來(lái)展開(kāi)的,但是我們?nèi)绻薷牧?Node 的相關(guān)標(biāo)簽,將 Node 添加到一個(gè) NodePool,Node 上對(duì)應(yīng)的屬性和 NodePool 的 status 信息也不會(huì)改變。如果我們想要實(shí)現(xiàn)上面的效果就需要監(jiān)聽(tīng)更多的資源變化。

在 controller 當(dāng)中我們可以看到一個(gè) SetupWithManager方法,這個(gè)方法說(shuō)明了我們需要監(jiān)聽(tīng)哪些資源的變化

 
 
 
 
  1. // SetupWithManager sets up the controller with the Manager.
  2. func (r *NodePoolReconciler) SetupWithManager(mgr ctrl.Manager) error {
  3.  return ctrl.NewControllerManagedBy(mgr).
  4.   For(&nodesv1.NodePool{}).
  5.   Complete(r)
  6. }

其中 NewControllerManagedBy是一個(gè)建造者模式,返回的是一個(gè) builder 對(duì)象,其包含了用于構(gòu)建的 For、Owns、Watches、WithEventFilter等方法

這里我們就可以利用 ``Watches方法來(lái)監(jiān)聽(tīng) Node 的變化,我們這里使用handler.Funcs`自定義了一個(gè)入隊(duì)器

監(jiān)聽(tīng) Node 對(duì)象的更新事件,如果存在和 NodePool 關(guān)聯(lián)的 node 對(duì)象更新就把對(duì)應(yīng)的 NodePool 入隊(duì)

 
 
 
 
  1. // SetupWithManager sets up the controller with the Manager.
  2. func (r *NodePoolReconciler) SetupWithManager(mgr ctrl.Manager) error {
  3.  return ctrl.NewControllerManagedBy(mgr).
  4.   For(&nodesv1.NodePool{}).
  5.   Watches(&source.Kind{Type: &corev1.Node{}}, handler.Funcs{UpdateFunc: r.nodeUpdateHandler}).
  6.   Complete(r)
  7. }
  8. func (r *NodePoolReconciler) nodeUpdateHandler(e event.UpdateEvent, q workqueue.RateLimitingInterface) {
  9.  ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  10.  defer cancel()
  11.  oldPool, err := r.getNodePoolByLabels(ctx, e.ObjectOld.GetLabels())
  12.  if err != nil {
  13.   r.Log.Error(err, "get node pool err")
  14.  }
  15.  if oldPool != nil {
  16.   q.Add(reconcile.Request{
  17.    NamespacedName: types.NamespacedName{Name: oldPool.Name},
  18.   })
  19.  }
  20.  newPool, err := r.getNodePoolByLabels(ctx, e.ObjectOld.GetLabels())
  21.  if err != nil {
  22.   r.Log.Error(err, "get node pool err")
  23.  }
  24.  if newPool != nil {
  25.   q.Add(reconcile.Request{
  26.    NamespacedName: types.NamespacedName{Name: newPool.Name},
  27.   })
  28.  }
  29. }
  30. func (r *NodePoolReconciler) getNodePoolByLabels(ctx context.Context, labels map[string]string) (*nodesv1.NodePool, error) {
  31.  pool := &nodesv1.NodePool{}
  32.  for k := range labels {
  33.   ss := strings.Split(k, "node-role.kubernetes.io/")
  34.   if len(ss) != 2 {
  35.    continue
  36.   }
  37.   err := r.Client.Get(ctx, types.NamespacedName{Name: ss[1]}, pool)
  38.   if err == nil {
  39.    return pool, nil
  40.   }
  41.   if client.IgnoreNotFound(err) != nil {
  42.    return nil, err
  43.   }
  44.  }
  45.  return nil, nil
  46. }

總結(jié)

今天我們完善了 status & event 和自定義對(duì)象 watch 下一篇我們看一下如何對(duì)我們的 Operator 進(jìn)行測(cè)試


網(wǎng)頁(yè)標(biāo)題:一篇帶你kubebuilder實(shí)戰(zhàn):status&event
當(dāng)前地址:http://www.dlmjj.cn/article/cdpjchc.html