bounty将在6天内到期。回答此问题可获得+100声望奖励。PJEM正在寻找一个从一个有信誉的来源的答案:我需要一个方法来做它根据最佳实践
我有k8s控制器,需要安装一些资源,并相应地更新状态和条件
协调中的流程如下所示:
1.安装资源,不要等待
1.调用函数checkAvailability
,如果就绪/待安装/错误,则相应地更新状态
我有两个主要问题:
1.这是我第一次使用状态和条件,这是正确的方法还是我错过了什么
1.有时当我更新r.Status().Update
时,我会得到错误:Operation cannot be fulfilled on eds.core.vtw.bmw.com “resouce01”: the object has been modified; please apply your changes to the latest version and try again , so I’ve added the check
conditionChanged`这解决了问题,但不确定其是否正确,因为我更新了状态一次,如果它没有吟唱,我就不碰它,这样用户就可以看到一段时间前的状态就绪,并且协调不会更新就绪条件的日期和时间,因为它在已经“就绪”时跳过它
我使用以下
func (r *ebdReconciler) checkHealth(ctx context.Context, req ctrl.Request, ebd ebdmanv1alpha1.ebd) (bool, error) {
vfmReady, err := r.mbr.IsReady(ctx, req.Name, req.Namespace)
condition := metav1.Condition{
Type: ebdmanv1alpha1.KubernetesvfmHealthy,
Observebdneration: ebd.Generation,
LastTransitionTime: metav1.Now(),
}
if err != nil {
// There was an error checking readiness - Set status to false
condition.Status = metav1.ConditionFalse
condition.Reason = ebdmanv1alpha1.ReasonError
condition.Message = fmt.Sprintf("Failed to check vfm readiness: %v", err)
} else if vfmReady {
// The vfm is ready - Set status to true
condition.Status = metav1.ConditionTrue
condition.Reason = ebdmanv1alpha1.ReasonReady
condition.Message = "vfm custom resource is ready"
} else {
// The vfm is not ready - Set status to false
condition.Status = metav1.ConditionFalse
condition.Reason = ebdmanv1alpha1.ResourceProgressing
condition.Message = "vfm custom resource is not ready"
}
// Get the latest version of the ebd
latestebd := ebdmanv1alpha1.ebd{}
if err := r.Get(ctx, req.NamespacedName, &latestebd); err != nil {
return vfmReady, err
}
oldConditions := latestebd.Status.Conditions
meta.SetStatusCondition(&latestebd.Status.Conditions, condition)
if !conditionChanged(&oldConditions, &latestebd.Status.Conditions, ebdmanv1alpha1.KubernetesvfmHealthy) {
return vfmReady, nil
}
if err := r.Status().Update(ctx, &latestebd); err != nil {
r.Log.Error(err, "failed to update vfm status")
return vfmReady, err
}
return vfmReady, nil
}
func conditionChanged(oldConditions, newConditions *[]metav1.Condition, conditionType string) bool {
newCondition := meta.FindStatusCondition(*newConditions, conditionType)
oldCondition := meta.FindStatusCondition(*oldConditions, conditionType)
if oldCondition == nil && newCondition == nil {
return false
}
if oldCondition == nil || newCondition == nil {
return true
}
return oldCondition.Status != newCondition.Status || oldCondition.Reason != newCondition.Reason || oldCondition.Message != newCondition.Message
}
1条答案
按热度按时间suzh9iv81#
回答您的问题:
1.这是我第一次使用状态和条件,这是正确的方式还是我错过了什么?
您管理Kubernetes资源的状态和条件的方法通常是好的。Kubernetes API对象中的
status
subresource通常用于表示系统的当前状态,它可以包含条件。条件是字段的集合,它们以比
true
或false
更详细的方式描述对象的状态。每个条件通常有type
、status
、reason
、message
和lastTransitionTime
。您的代码根据vfm
自定义资源是否就绪来正确设置这些字段。值得注意的是,条件应该是水平的-这意味着它们应该被设置为它们的当前观察值,而不管它们的先前值如何。还应该为组件当前状态的所有重要或用户有意义的方面设置它们(
true
、false
或unknown
)。这使得条件成为一种很好的机制来指示“ transient ”,如Progressing
或Degraded
,这些 transient 可能会随着时间的推移或基于外部状态而改变。1.有时当我更新
r.Status().Update
时,我会得到错误:Operation cannot be fulfilled on eds.core.vtw.bmw.com “resource01”: the object has been modified; please apply your changes to the latest version and try again
.发生此错误的原因是,在控制器处理同一对象时,另一个客户端更新了该对象。这可能是另一个控制器,甚至是同一个控制器的另一个示例(如果您运行多个控制器)。
处理此问题的一种可能方法是使用重试机制,在发生此错误时重新尝试状态更新。在本例中,您实现了
conditionChanged
检查,以便仅在条件发生更改时尝试状态更新。这是避免不必要的更新的好方法,但它不能完全防止错误,因为另一个客户端仍然可以在您的Get
调用和Status().Update
调用之间更新对象。您还可以考虑使用
Patch
而不是Update
来修改状态,这可以降低与其他更新冲突的风险。打补丁允许对对象进行部分更新,因此您不太可能遇到冲突。关于时间问题,您可以考虑仅在状态实际发生变化时更新
LastTransitionTime
,而不是每次完成健康检查时都更新。这意味着LastTransitionTime
反映的是状态上次更改的时间,而不是上次执行检查的时间。需要记住的一点是,频繁更新状态子资源,即使状态没有改变,也会导致不必要的API服务器负载。您应该努力仅在状态发生更改时才更新状态。
考虑到这些点,
checkHealth
函数的可能更新版本可能是:在此更新版本中:
LastTransitionTime
字段仅在条件的状态更改时更新。这将确保LastTransitionTime
准确地反映状态上次更改的时间,而不是checkHealth
函数上次运行的时间。这将提供一个更准确的时间轴,说明资源的状态实际发生更改的时间,而不是协调循环运行的时间。retry.RetryOnConflict
添加了重试机制,以便在发生冲突错误时重新尝试状态更新。请注意,您需要为此导入"k8s.io/client-go/util/retry
" package。这是处理
Operation cannot be fulfilled...
错误的常见模式。这些更改应该有助于解决您在更新Kubernetes资源的状态和条件时所面临的问题。
请记住,您可能偶尔仍会遇到冲突错误,特别是当有其他客户端更新同一对象时。在这些情况下,
RetryOnConflict
函数将使用对象的最新版本重试更新。