踩坑client-go for kubernetes乐观锁

直接上一段代码

func (po *PreOccupy) SetPodAnnotation(pod *v1.Pod) error {
   clientSet := po.Handle.ClientSet()
 
   if _, ok := pod.Annotations[OccupyExpireTime]; ok {
      pod.Annotations[OccupyExpireTime] = ""
   }
   if _, ok := pod.Annotations[OccupyKilled]; ok {
      pod.Annotations[OccupyKilled] = "false"
   }
   _, err := clientSet.CoreV1().Pods(pod.Namespace).Update(context.TODO(), pod, metav1.UpdateOptions{})
   if err != nil {
      return err
   }
 
   return nil
}

代码理解起来很简单,声明一个client,使用client,更新一条数据。但是这段代码会发生一个错误,在日志中提示说:无法修改pod的内置对象数据,请重试或者强制更新。

ResourceVersion登场

ResourceVersion是kubernetes实现乐观锁的方式,ResourceVersion是服务器来控制,使用的是ETCD中的modifiedIndex值。是不是我随便修改一下提交上去,不是。
ResourceVersion是服务器来控制,client修改了也会被controller-manager认为失败。

优化代码

func (po *PreOccupy) SetCacheNodeName(pod *v1.Pod, nodeName string) error {
   clientSet := po.Handle.ClientSet()
   retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
      if _, ok := pod.Annotations[OccupyExpireTime]; ok {
         if _, ok := pod.Annotations[OccupyNodeName]; ok {
            newPod, err := clientSet.CoreV1().Pods(pod.Namespace).Get(context.TODO(), pod.Name, metav1.GetOptions{})
            if err != nil {
               return err
            }
            newPod.Annotations[OccupyNodeName] = nodeName
            _, err = clientSet.CoreV1().Pods(newPod.Namespace).Update(context.TODO(), newPod, metav1.UpdateOptions{})
            if err != nil {
               return err
            }
         }
      }
 
      return nil
   })
 
   if retryErr != nil {
      return retryErr
   }
 
   return nil
}

上述代码并没有明显出现提交ResourceVersion,注意代码11行,在update操作时,直接使用的newPod,而非pod数据。这就是相当于全量提交了最新的pod数据。

不得不说,社区设计的真是巧妙。

RetryOnConflict

retry是如果你担心你的update、get、list、create等操作发生错误,系统会自动帮你重试,设计的也同时很巧妙。

代码原文解释

RetryOnConflict is used to make an update to a resource when you have to worry about
conflicts caused by other code making unrelated updates to the resource at the same
time. fn should fetch the resource to be modified, make appropriate changes to it, try
to update it, and return (unmodified) the error from the update function. On a
successful update, RetryOnConflict will return nil. If the update function returns a
“Conflict” error, RetryOnConflict will wait some amount of time as described by
backoff, and then try again. On a non-“Conflict” error, or if it retries too many times
and gives up, RetryOnConflict will return an error to the caller.

至此,问题解决了。这种client的方式多用于client主动修改k8s的资源,也可以用于并发场景。

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=344hdj96dhesc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xf491698144

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值