Skip to content

Commit

Permalink
Add Resource Version semantics section to api concepts
Browse files Browse the repository at this point in the history
  • Loading branch information
jpbetz committed Oct 15, 2019
1 parent cf7992e commit 987a15d
Showing 1 changed file with 115 additions and 1 deletion.
116 changes: 115 additions & 1 deletion content/en/docs/reference/using-api/api-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The verbs supported for each subresource will differ depending on the object - s

## Efficient detection of changes

To enable clients to build a model of the current state of a cluster, all Kubernetes object resource types are required to support consistent lists and an incremental change notification feed called a **watch**. Every Kubernetes object has a `resourceVersion` field representing the version of that resource as stored in the underlying database. When retrieving a collection of resources (either namespace or cluster scoped), the response from the server will contain a `resourceVersion` value that can be used to initiate a watch against the server. The server will return all changes (creates, deletes, and updates) that occur after the supplied `resourceVersion`. This allows a client to fetch the current state and then watch for changes without missing any updates. If the client watch is disconnected they can restart a new watch from the last returned `resourceVersion`, or perform a new collection request and begin again.
To enable clients to build a model of the current state of a cluster, all Kubernetes object resource types are required to support consistent lists and an incremental change notification feed called a **watch**. Every Kubernetes object has a `resourceVersion` field representing the version of that resource as stored in the underlying database. When retrieving a collection of resources (either namespace or cluster scoped), the response from the server will contain a `resourceVersion` value that can be used to initiate a watch against the server. The server will return all changes (creates, deletes, and updates) that occur after the supplied `resourceVersion`. This allows a client to fetch the current state and then watch for changes without missing any updates. If the client watch is disconnected they can restart a new watch from the last returned `resourceVersion`, or perform a new collection request and begin again. See [Resource Version Semantics](#resource-version-semantics) for more detail.

For example:

Expand Down Expand Up @@ -87,6 +87,63 @@ For example:

A given Kubernetes server will only preserve a historical list of changes for a limited time. Clusters using etcd3 preserve changes in the last 5 minutes by default. When the requested watch operations fail because the historical version of that resource is not available, clients must handle the case by recognizing the status code `410 Gone`, clearing their local cache, performing a list operation, and starting the watch from the `resourceVersion` returned by that new list operation. Most client libraries offer some form of standard tool for this logic. (In Go this is called a `Reflector` and is located in the `k8s.io/client-go/cache` package.)

### Reflectors

A reflector is a client side component that watches a specified resource and causes all changes to be reflected in the given store.

The following pseudo-code demonstrates how a client implement a reflector. The client recovers from `410 Gone` responses by "relisting", which enables it to watch resources indefinitely:

```
// Must be a specific resource version if the client requires data no older than a known resource version.
// If not, this can initialized to "0".
lastObservedResourceVersion := initialResourceVersion
while(should continue watching) {
send HTTP LIST request with parameter: resourceVersion=lastObservedResourceVersion
switch(HTTP response status code) {
case 410: // "Gone"
// next relist must be for most recent resource version
lastObservedResourceVersion = ""
case 200: // "OK"
// Set the store to the contents of the list response.
// This may either be the 1st list, which determines initial state, or it might
// be a "relist", which re-establishes state after a watch is dropped.
lastObservedResourceVersion = `metadata.resourceVersion` in HTTP response
send HTTP WATCH request with parameter: resourceVersion=lastObservedResourceVersion
switch(HTTP response status code) {
case 410: // "Gone"
// next relist must be for most recent resource version
lastObservedResourceVersion = ""
}
case 200: // "OK":
while(watch HTTP response not closed) {
foreach(HTTP response chunked response part) {
switch(HTTP response status code) {
case 410: // "Gone"
// next relist must be for most recent resource version
lastObservedResourceVersion = ""
case 200:
// Apply the watch event to the store.
lastObservedResourceVersion := resourceVersion of watch event
default:
// handle errors
}
}
}
}
default:
// handle errors
}
default:
// handle errors
}
}
```

### Watch bookmarks

{{< feature-state for_k8s_version="v1.16" state="beta" >}}
Expand Down Expand Up @@ -617,3 +674,60 @@ Server Side Apply is a beta feature, so it is enabled by default. To turn this
you need to include the `--feature-gates ServerSideApply=false` flag when
starting `kube-apiserver`. If you have multiple `kube-apiserver` replicas, all
should have the same flag setting.

## Resource Version Semantics

Resource versions are strings that identify the server's internal version of an object. They can used by clients to determine when objects have changed, or to express data consistency requirements when getting, listing and watching resources. Resource versions must be treated as opaque by clients and passed unmodified back to the server.

### ResourceVersion in metadata

Clients find resource versions in resources and list responses returned from the server:

[v1.meta/ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/#objectmeta-v1-meta) - The `metadata.resourceVersion` of a resource instance identifies the resource version the instance was last modified at.

[v1.meta/ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/#listmeta-v1-meta) - The `metadata.resourceVersion` of a resource collection (i.e. a list response) identifies the resource version at which the list response was constructed.

### The ResourceVersion Parameter

The get, list and watch operations support a `resourceVersion` parameter.

The exact meaning of this parameter differs depending on the operation and the value of the resource version.

For get and list, the semantics of resource version are:

- **Most Recent:** Return data at the most recent resource version. The returned data must be consistent (i.e. served from etcd via a quorum read).
- **Not older than:** Return data at least as new as the provided resource version. The newest available resource version is preferred but strong consistency is not required; any data not older than this resource version is sufficient. In high availabiliy configurations, it is possible for the watch to start at a much older resource version that the client has previously observed, due to partitions or stale caches. Clients that cannot tolerate this should not use this semantic.
- **Exact:** Return data at the exact resource version provided.

And the possible cases are:

**Get:**

| resourceVersion unset | resourceVersion="0" | resourceVersion="{non-zero version}" |
|-----------------------|---------------------|--------------------------------------|
| Most Recent | Not older than | Not older than |

**List:**

| paging | resourceVersion unset | resourceVersion="0" | resourceVersion="{non-zero version}" |
|-----------|-----------------------|---------------------|--------------------------------------|
| no limit | Most Recent | Not older than | Not older than |
| limit="n" | Most Recent | Not older than | Exact |

For watch, the semantics are:

- **Start at Most Recent:** Start a watch at the most recent resource version, which must be consistent (i.e. served from etcd via a quorum read). The establish initial state, the watch events begin with “Added” events for all resources instances that exist at the starting resource version. The following watch events are for all changes that occured after the resource version the watch started at.
- **Start at Any:** Start a watch at any resource version, the most recent resource version available is preferred, but not required; any starting resource version is allowed. In high availabiliy configurations, it is possible for the watch to start at a much older resource version that the client has previously observed, due to partitions or stale caches. Clients that cannot tolerate this should not start a watch with this semantic. The establish initial state, the watch events begin with “Added” events for all resources instances that exist at the starting resource version. The following watch events are for all changes that occured after the resource version the watch started at.
- **Start at Exact:** Start a watch at an exact resource version. The watch events are for all changes after the provided resource version. Unlike "Start at Most Recent" and "Start at Any", the watch is not started with "Added" events for the provided resource version. The client is assumed to already have the state at the provided resource version.

And the possible cases are:

**Watch:**

| resourceVersion unset | resourceVersion="0" | resourceVersion="{non-zero version}" |
|-----------------------|---------------------|--------------------------------------|
| Start at Most Recent | Start at Any | Start at Exact |

### "Gone" resource versions

Servers are not required to serve all older resource versions and may return a HTTP `410 (Gone)` status code if a client requests a resourceVersion older than the server has retained. Clients must be able to tolerate `410 (Gone)` responses. For example, clients watching resources can tolerate `410 (Gone)` by relisting at a newer resource version and resuming a watch from there.

0 comments on commit 987a15d

Please sign in to comment.