关于ReplicaSet与StatefulSet的CreationTimestamp(AGE)变更场景及资源最近更新验证方法的技术问询
Understanding ReplicaSet/StatefulSet AGE and Detecting Recent Updates
First: What Changes the CreationTimestamp (AGE) of ReplicaSets and StatefulSets?
The CreationTimestamp field is set only once when the resource is first created. No subsequent modifications to the resource (whether to its spec, metadata, or status) will update this value. Here's how this plays out for each resource:
ReplicaSets:
- A new ReplicaSet gets a fresh
CreationTimestamponly when a Deployment triggers a rollout (e.g., changing container images, resource limits, pod template labels, or any other field that requires a new pod template). - When you roll back to an older Deployment revision, Kubernetes reuses the existing old ReplicaSet (setting its
DESIREDreplicas back to the target count) instead of creating a new one. That's why the old ReplicaSet's AGE stays the same. - Modifying an existing ReplicaSet directly (e.g., scaling it manually) won't change its
CreationTimestamp.
- A new ReplicaSet gets a fresh
StatefulSets:
- Unlike Deployments, StatefulSets don't create multiple versions of themselves. All updates are applied directly to the existing StatefulSet resource.
- This means the
CreationTimestampof a StatefulSet will never change unless you delete the StatefulSet and recreate it from scratch. Even rolling updates or template changes won't update this field.
Second: Best Ways to Verify Recent Updates for Deployments, ReplicaSets, and StatefulSets
Checking CreationTimestamp (AGE) isn't reliable because it doesn't reflect in-place updates or rollbacks. Instead, use these fields and annotations:
For ReplicaSets:
metadata.annotations["deployment.kubernetes.io/revision"]: Tracks the Deployment's revision number this ReplicaSet belongs to. A higher revision number means a more recent update.metadata.generationvsstatus.observedGeneration: Every time you modify the ReplicaSet's spec,metadata.generationincrements. When the controller finishes processing the change,status.observedGenerationmatches it. A recent gap or match can indicate a recent update.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"]: Added automatically when you runkubectl rollout restart deployment—this timestamp tells you when the pods were last restarted.- Check if the ReplicaSet is the active one for its Deployment (match
deployment.status.currentReplicaSetNameto the ReplicaSet's name) and then inspect its status conditions.
For StatefulSets:
metadata.generationvsstatus.observedGeneration: Same logic as ReplicaSets—an increment ingenerationfollowed byobservedGenerationcatching up indicates a recent spec change.status.currentRevisionvsstatus.updateRevision: If these differ, the StatefulSet is in the middle of an update. When the update completes, they'll match.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"]: Same as ReplicaSets—tracks manual restarts.status.conditions: Look for conditions likeStatefulSetUpdatedorStatefulSetReadyand check theirLastTransitionTimeto see when the last update finished.
For Deployments:
metadata.annotations["deployment.kubernetes.io/revision"]: Increments with every rollout/rollback.status.updatedReplicas: Should matchstatus.replicaswhen an update is complete.status.conditions: TheAvailableorProgressingconditions haveLastTransitionTimefields that mark recent updates.
Revising Your client-go Code
Here's how to adjust your functions to detect recent updates more accurately, moving away from relying on CreationTimestamp:
Updated StatefulSet Check
import ( "context" "errors" "fmt" "log" "time" "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" appsv1 "k8s.io/api/apps/v1" ) func statefulsetCheck(namespace string, clientset *kubernetes.Clientset) bool { statefulsets, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), v1.ListOptions{}) if errors.IsNotFound(err) { log.Fatal("\nNo statefulsets in the namespace", err) } else if err != nil { log.Fatal("\nFailed to fetch statefulsets in the namespace: ", err) } var stsNames []string for _, sts := range statefulsets.Items { stsNames = append(stsNames, sts.Name) } fmt.Printf("\nStatefulsets in the namespace: %v", stsNames) // Check for recent updates using conditions and restart annotations for _, sts := range statefulsets.Items { // Check if the StatefulSet was recently updated via spec changes for _, cond := range sts.Status.Conditions { if cond.Type == appsv1.StatefulSetUpdated { lastUpdate := cond.LastTransitionTime.Time if time.Since(lastUpdate).Minutes() < 5 { fmt.Printf("\nStatefulset %v had recent spec updates. Skipping...", sts.Name) return true } } } // Check if pods were recently restarted via kubectl rollout restart restartedAtStr := sts.Spec.Template.ObjectMeta.Annotations["kubectl.kubernetes.io/restartedAt"] if restartedAtStr != "" { restartedAt, err := time.Parse(time.RFC3339, restartedAtStr) if err == nil && time.Since(restartedAt).Minutes() < 5 { fmt.Printf("\nStatefulset %v was recently restarted. Skipping...", sts.Name) return true } } } return false }
Updated ReplicaSet Check
func replicasetCheck(namespace string, clientset *kubernetes.Clientset) bool { replicasets, err := clientset.AppsV1().ReplicaSets(namespace).List(context.TODO(), v1.ListOptions{}) if errors.IsNotFound(err) { log.Fatal("\nNo replicasets in the namespace", err) } else if err != nil { log.Fatal("\nFailed to fetch replicasets in the namespace: ", err) } var rpsNames []string for _, rps := range replicasets.Items { rpsNames = append(rpsNames, rps.Name) } fmt.Printf("\nReplicasets in the namespace: %v", rpsNames) for _, rps := range replicasets.Items { // Check if this is the active ReplicaSet for its Deployment (focus on relevant RS) deploymentName := rps.ObjectMeta.Annotations["deployment.kubernetes.io/name"] if deploymentName != "" { deployment, err := clientset.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, v1.GetOptions{}) if err == nil && deployment.Status.CurrentReplicaSetName == rps.Name { // Check recent update via Ready condition for _, cond := range rps.Status.Conditions { if cond.Type == appsv1.ReplicaSetReady { lastReadyTime := cond.LastTransitionTime.Time if time.Since(lastReadyTime).Minutes() < 5 { fmt.Printf("\nActive ReplicaSet %v (for Deployment %v) had recent updates...", rps.Name, deploymentName) return true } } } } } // Check for recent pod restarts restartedAtStr := rps.Spec.Template.ObjectMeta.Annotations["kubectl.kubernetes.io/restartedAt"] if restartedAtStr != "" { restartedAt, err := time.Parse(time.RFC3339, restartedAtStr) if err == nil && time.Since(restartedAt).Minutes() < 5 { fmt.Printf("\nReplicaSet %v was recently restarted...", rps.Name) return true } } } return false }
内容的提问来源于stack exchange,提问作者Kaio H. Cunha
相关产品推荐
相关产品推荐

