Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between a resourceVersion and a generation?

Tags:

kubernetes

In Kubernetes object metadata, there are the concepts of resourceVersion and generation. I understand the notion of resourceVersion: it is an optimistic concurrency control mechanism—it will change with every update. What, then, is generation for?

like image 548
Laird Nelson Avatar asked Nov 03 '17 16:11

Laird Nelson


2 Answers

resourceVersion changes on every write, and is used for optimistic concurrency control

in some objects, generation is incremented by the server as part of persisting writes affecting the spec of an object.

some objects' status fields have an observedGeneration subfield for controllers to persist the generation that was last acted on.

like image 102
Jordan Liggitt Avatar answered Oct 26 '22 02:10

Jordan Liggitt


In a Deployment context:

In Short

resourceVersion is the version of a k8s resource, while generation is the version of the deployment which you can use to undo, pause and so on using kubectl cli.

Source code for kubectl rollout: https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/rollout/rollout.go#L50

The Long Version

resourceVersion

K8s server saves all the modifications to any k8s resource. Each modification has a version which is called resourceVersion.

k8s languages libraries provide a way to receive in real-time events of ADD, DELETE, MODIFY events of any resource. You also have BOOKMARK event, but let's leave that for a moment aside.

On any modification operation, you receive the new k8s resource with updated resourceVersion. You can use this resourceVersion and start a watch starting from this resourceVersion, so you won't miss any events between the time the k8s server sent you back the first response, until the watch has started.

  • K8s doesn't preserve the history for every resource for ever. I think that it will save for 5m, but I'm not sure exactly.

resourceVersion will change after any modification of the object.

The reason of it's existence is to avoid concurrency problems where multiple clients try to modify the same k8s resource. This pattern is pretty common also in databases and you can find more info about it:

  • Optimistic concurrency control (https://en.wikipedia.org/wiki/Optimistic_concurrency_control)
  • https://www.programmersought.com/article/1104647506/

observedGeneration

You didn't talk about it in your question but thats important piece of information we need to clarify before moving on to generation.

It is the version of the replicaSet which this deployment is currently tracking on.

When the deployment is still creating for the first time, this value won't exist (good discussion on this can be found here: https://github.com/kubernetes/kubernetes/issues/47871).

This value can be found under status:

....
apiVersion: apps/v1
kind: Deployment
.....
status:
  availableReplicas: 1
  conditions:
  - lastTransitionTime: "2021-02-07T19:04:17Z"
    lastUpdateTime: "2021-02-07T19:04:17Z"
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Available
  - lastTransitionTime: "2021-02-07T19:04:15Z"
    lastUpdateTime: "2021-02-07T19:17:09Z"
    message: ReplicaSet "deployment-bcb437a4-59bb9f6f69" has successfully progressed.
    reason: NewReplicaSetAvailable
    status: "True"
    type: Progressing
  observedGeneration: 3.    <<<--------------------
  readyReplicas: 1
  replicas: 1
  updatedReplicas: 1
  • p.s, from this article: https://thenewstack.io/kubernetes-deployments-work/

observedGeneration is equal to the deployment.kubernetes.io/revision annotation. It is the observedGeneration.

It looks correct because deployment.kubernetes.io/revision does not exist when the deployment is first created and not yet ready, and also it has the same value as observedGeneration when the deployment is updated.


generation

It represents the version of the "new" replicaSet which this deployment should track on.

When a deployment is created for the first time, the value of this will be equal to 1. When the observedGeneration will be set to 1, it means that replicate set is ready (This question is not about how to know if a deployment was successful (or not) so I'm not getting into what is "ready", which is some terminology I created for this answer - but be sure that there are additional conditions to check if a deployment was successful or not).

Same goes for any change in the deployment k8s resource which will trigger re-deployment. the generation value will be incremented by 1, and then it will take some time until observedGeneration will be equal to generation value.

More info on observedGeneration and generation in the context of kuebctl rollout status (to check if a deployment "finished") from kubectl source code:

https://github.com/kubernetes/kubectl/blob/a2d36ec6d62f756e72fb3a5f49ed0f720ad0fe83/pkg/polymorphichelpers/rollout_status.go#L75

if deployment.Generation <= deployment.Status.ObservedGeneration {
        cond := deploymentutil.GetDeploymentCondition(deployment.Status, appsv1.DeploymentProgressing)
        if cond != nil && cond.Reason == deploymentutil.TimedOutReason {
            return "", false, fmt.Errorf("deployment %q exceeded its progress deadline", deployment.Name)
        }
        if deployment.Spec.Replicas != nil && deployment.Status.UpdatedReplicas < *deployment.Spec.Replicas {
            return fmt.Sprintf("Waiting for deployment %q rollout to finish: %d out of %d new replicas have been updated...\n", deployment.Name, deployment.Status.UpdatedReplicas, *deployment.Spec.Replicas), false, nil
        }
        if deployment.Status.Replicas > deployment.Status.UpdatedReplicas {
            return fmt.Sprintf("Waiting for deployment %q rollout to finish: %d old replicas are pending termination...\n", deployment.Name, deployment.Status.Replicas-deployment.Status.UpdatedReplicas), false, nil
        }
        if deployment.Status.AvailableReplicas < deployment.Status.UpdatedReplicas {
            return fmt.Sprintf("Waiting for deployment %q rollout to finish: %d of %d updated replicas are available...\n", deployment.Name, deployment.Status.AvailableReplicas, deployment.Status.UpdatedReplicas), false, nil
        }
        return fmt.Sprintf("deployment %q successfully rolled out\n", deployment.Name), true, nil
    }
    return fmt.Sprintf("Waiting for deployment spec update to be observed...\n"), false, nil

I must say that I'm not sure when a observedGeneration can be higher than generation. Maybe folks can help me out in the comments.


To sum it all up: Illustration from this great article: https://thenewstack.io/kubernetes-deployments-work/ enter image description here

More Info:

  • https://kubernetes.slack.com/archives/C2GL57FJ4/p1612651711106700?thread_ts=1612650049.105300&cid=C2GL57FJ4
  • Some more information about Bookmarks Events (Which are related to resourceVersion: What k8s bookmark solves?
  • How do you rollback deployments in Kubernete: https://learnk8s.io/kubernetes-rollbacks
like image 7
Stav Alfi Avatar answered Oct 26 '22 02:10

Stav Alfi