如何获取k8s中StatefulSet的最新更改时间

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

How to get the latest change time of StatefulSet in k8s

问题

我知道,例如,你可以使用 kubectl 获取 Deployment 的 lastUpdateTime:

kubectl get deploy <deployment-name> -o jsonpath={.status.conditions[1].lastUpdateTime}

或者通过 client-go

func deploymentCheck(namespace string, clientset *kubernetes.Clientset) bool {
	// 获取命名空间中的 deployments
	deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
	if errors.IsNotFound(err) {
		log.Fatal("\n命名空间中没有 deployments", err)
	} else if err != nil {
		log.Fatal("\n获取命名空间中的 deployments 失败", err)
	}

	var dptNames []string
	for _, dpt := range deployments.Items {
		dptNames = append(dptNames, dpt.Name)
	}
	// 检查 deployments 的最后更新时间
	for _, dpt := range deployments.Items {
		lastUpdateTime := dpt.Status.Conditions[1].LastUpdateTime
		dptAge := time.Since(lastUpdateTime.Time)
		fmt.Printf("\nDeployment %v 的年龄:%v", dpt.Name, dptAge)
	}
}

对于 StatefulSet,似乎没有类似于 lastUpdateTime := dpt.Status.Conditions[1].LastUpdateTime 的等效方法。

那么,我如何获取 StatefulSet 的 lastUpdateTime?

英文:

I know, for example, that you can get the lastUpdateTime of a Deployment with kubectl:

kubectl get deploy &lt;deployment-name&gt; -o jsonpath={.status.conditions[1].lastUpdateTime}

Or via client-go:

func deploymentCheck(namespace string, clientset *kubernetes.Clientset) bool {
	// get the deployments in the namespace
	deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
	if errors.IsNotFound(err) {
		log.Fatal(&quot;\nNo deployments in the namespace&quot;, err)
	} else if err != nil {
		log.Fatal(&quot;\nFailed to fetch deployments in the namespace&quot;, err)
	}

	var dptNames []string
	for _, dpt := range deployments.Items {
		dptNames = append(dptNames, dpt.Name)
	}
	// check the last update time of the deployments
	for _, dpt := range deployments.Items {
		lastUpdateTime := dpt.Status.Conditions[1].LastUpdateTime
		dptAge := time.Since(lastUpdateTime.Time)
		fmt.Printf(&quot;\nDeployment %v age: %v&quot;, dpt.Name, dptAge)
	}
}

The equivalent of lastUpdateTime := dpt.Status.Conditions[1].LastUpdateTime for a StatefulSet doesn't seem to exist.

So, how can I get the lastUpdateTime of a StatefulSet?

答案1

得分: 1

我注意到在某人编辑给定资源后,唯一会发生变化的是该资源的lastAppliedConfiguration、Generation和ObservedGeneration。所以,我将它们存储在列表中:

	for _, deployment := range deployments.Items {
		deploymentNames = append(deploymentNames, deployment.Name)
		lastAppliedConfig := deployment.GetAnnotations()["kubectl.kubernetes.io/last-applied-configuration"]

		lastAppliedConfigs = append(lastAppliedConfigs, lastAppliedConfig)
		generations = append(generations, deployment.Generation)
		observedGenerations = append(observedGenerations, deployment.Status.ObservedGeneration)
	}

以下是完整的函数:

func DeploymentCheck(namespace string, clientset *kubernetes.Clientset) ([]string, []string, []int64, []int64) {

	var deploymentNames []string
	var lastAppliedConfigs []string
	var generations []int64
	var observedGenerations []int64

	deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
	if errors.IsNotFound(err) {
		log.Print("No deployments in the namespace", err)
	} else if err != nil {
		log.Print("Failed to fetch deployments in the namespace", err)
	}

	for _, deployment := range deployments.Items {
		deploymentNames = append(deploymentNames, deployment.Name)
		lastAppliedConfig := deployment.GetAnnotations()["kubectl.kubernetes.io/last-applied-configuration"]

		lastAppliedConfigs = append(lastAppliedConfigs, lastAppliedConfig)
		generations = append(generations, deployment.Generation)
		observedGenerations = append(observedGenerations, deployment.Status.ObservedGeneration)
	}

	return deploymentNames, lastAppliedConfigs, generations, observedGenerations
}

我使用所有这些信息来实例化一个名为Namespace的结构体,其中包含一个k8s命名空间可能拥有的所有主要资源。

然后,在一段时间后,我再次检查同一个命名空间,并检查其资源是否有任何更改:

if !reflect.DeepEqual(namespace.stsLastAppliedConfig, namespaceCopy.stsLastAppliedConfig) {
...
}
else if !reflect.DeepEqual(namespace.stsGeneration, namespaceCopy.stsGeneration) {
...
}
else if !reflect.DeepEqual(namespace.stsObservedGeneration, namespaceCopy.stsObservedGeneration) {
...
}

所以,我找到的唯一解决方法是在一段时间后比较资源的配置,包括StatefulSets的配置。显然,对于某些资源,您无法获取有关其lastUpdateTime的任何信息。

我还发现lastUpdateTime实际上是不可靠的,因为它将次要的集群更改视为资源的更改。例如,如果集群旋转并杀死所有pod,Deployment的lastUpdateTime将更新其时间。这不是我想要的。我想检测用户对资源的更改,比如当有人应用编辑过的yaml文件或运行kubectl edit时。

@hypperster,希望对您有所帮助。

英文:

I noticed that the only things that change after someone edits a given resource are the resource's lastAppliedConfiguration, Generation and ObservedGeneration. So, I stored them in lists:

	for _, deployment := range deployments.Items {
		deploymentNames = append(deploymentNames, deployment.Name)
		lastAppliedConfig := deployment.GetAnnotations()[&quot;kubectl.kubernetes.io/last-applied-configuration&quot;]

		lastAppliedConfigs = append(lastAppliedConfigs, lastAppliedConfig)
		generations = append(generations, deployment.Generation)
		observedGenerations = append(observedGenerations, deployment.Status.ObservedGeneration)
	}

Here's the full function:

func DeploymentCheck(namespace string, clientset *kubernetes.Clientset) ([]string, []string, []int64, []int64) {

	var deploymentNames []string
	var lastAppliedConfigs []string
	var generations []int64
	var observedGenerations []int64

	deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
	if errors.IsNotFound(err) {
		log.Print(&quot;No deployments in the namespace&quot;, err)
	} else if err != nil {
		log.Print(&quot;Failed to fetch deployments in the namespace&quot;, err)
	}

	for _, deployment := range deployments.Items {
		deploymentNames = append(deploymentNames, deployment.Name)
		lastAppliedConfig := deployment.GetAnnotations()[&quot;kubectl.kubernetes.io/last-applied-configuration&quot;]

		lastAppliedConfigs = append(lastAppliedConfigs, lastAppliedConfig)
		generations = append(generations, deployment.Generation)
		observedGenerations = append(observedGenerations, deployment.Status.ObservedGeneration)
	}

	return deploymentNames, lastAppliedConfigs, generations, observedGenerations
}

I use all this information to instantiate a struct called Namespace, which contains all major resources a k8s namespace can have.

Then, after a given time I check the same namespace again and check if its resources had any changes:

if !reflect.DeepEqual(namespace.stsLastAppliedConfig, namespaceCopy.stsLastAppliedConfig) {
...
}
else if !reflect.DeepEqual(namespace.stsGeneration, namespaceCopy.stsGeneration) {
...
}
else if !reflect.DeepEqual(namespace.stsObservedGeneration, namespaceCopy.stsObservedGeneration) {
...
}

So, the only workaround I found was to compare the resource's configuration, including StatefulSets', after a given time. Apparently, for some resources you cannot get any information about their lastUpdateTime.

I also found out that lastUpdateTime is actually not reliable, as it understands minor cluster changes as the resource's change. For example, if a cluster rotates and kills all pods, the lastUpdateTime of a Deployment will update its time. That's not what I wanted. I wanted to detect user changes to resources, like when someone applies an edited yaml file or run kubectl edit.

@hypperster , I hope it helps.

huangapple
  • 本文由 发表于 2022年3月31日 07:08:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/71685090.html
匿名

发表评论

匿名网友

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

确定