Drift
How the observer compares the live objects with the desired render, and how automatic mode corrects drift.
Drift is a difference between the live objects on the target cluster and the desired render of a
Release. The observer looks for drift in a loop and writes the result to the InSync condition.
In automatic sync mode, the observer then requests a /sync, and the controller applies the
render again.
The desired render#
The observer uses the same render that the controller keeps on the cluster. It selects the first item that applies:
- The pinned render, if the Release has a pin and the render store contains that render.
- The last healthy render, if the rollout is
RolledBackand the render store contains that render. - A fresh render of the current source, content and mutations.
Without this order, a pinned or rolled-back Release would always show drift. The /preview
subresource returns the same desired render. See Pin and history.
In manual mode, the fresh render can be newer than the applied render. Then InSync is False
until a /sync request applies the new render.
How the observer compares#
For each object of the desired render, the observer:
- Reads the live object. If the object does not exist, its status is
Missing. - Sends the desired object as a server-side apply dry run, with field manager
convoyandforce. This is the same request as the real apply, without a change on the cluster. - Clears these fields in the live object and in the dry-run result:
metadata.resourceVersion,metadata.uid,metadata.generation,metadata.creationTimestamp,metadata.managedFieldsandstatus. - Compares the two results. Each difference is a field change. With one or more changes, the status is
Modified. With no change, the status isInSync.
Both sides of the compare come from the API server. So server-side defaults and admission changes are on both sides and do not show as drift.
A field that another field manager owns, and that the render does not set, does not show as drift. A field that the render sets, and that another manager changed, shows as drift.
The InSync condition#
The observer writes InSync with field manager convoy-observe. It writes only when the
condition or the generation of the Release changes.
InSync(True): all objects areInSync.Drifted(False): at least one object isModifiedorMissing.Undetermined(Unknown): the observer could not complete the compare.
The compare stops at the first error, and the result is Undetermined. Examples of errors:
- The source or the render failed.
- The
Clusterdoes not exist or is not reachable. - The cluster does not know the kind of an object. For example, its CRD is not installed yet.
- The cluster rejected the dry run of an object.
The observer does not retry an Undetermined result with backoff. It checks again at the next
interval.
InSync · written by convoy-observer (field manager convoy-observe)
| Reason | Status | Meaning |
|---|---|---|
InSync | True | The live objects match the desired render. |
Drifted | False | At least one live object differs from the desired render, or is missing. In automatic sync mode, the observer requests a /sync. |
Undetermined | Unknown | The observer could not compare the live state with the render, for example because the cluster is not reachable. |
Self-heal#
The mode in spec.syncPolicy.automatic controls what occurs after the compare:
- Automatic mode. On
Drifted, the observer sendsPOST /sync. The controller reconciles and applies the full render again, which corrects the drift. - Manual mode. The observer only writes
InSync. convoy changes nothing until you send a/syncrequest.
In automatic mode, the controller also applies the full render at each periodic reconcile. So the controller corrects drift also without the observer. See Sync policy.
When the observer checks#
The observer runs a drift pass for a Release when one of these events occurs:
- The Release is created, or its
specchanges. - The controller applies a different render, which changes the
ReleaseInventory. - The time of
spec.syncPolicy.intervalpasses after the previous pass. - The informer resync of the observer occurs. The default period is 2 minutes (flag
--resync).
A /sync request does not start a drift pass. The observer does not watch the target cluster. A
change on the cluster shows at the next pass. The observer skips a Release that is being
deleted.
The /diff subresource#
GET releases/<name>/diff uses the same compare engine as the drift loop. So /diff and
InSync always agree. /diff returns the status and the field changes of each object. With
render=<renderRef>, it compares a stored render with the live objects. See
Release diff.
Only declared objects#
The observer checks only the objects of the desired render. It does not report a live object that convoy applied before but the render no longer contains. It also does not report other objects in the target namespaces. Detection of these extra objects is planned. Not built
The prune deletes objects that the render no longer contains. See Apply and prune.
In the code
convoy v0.9.0
internal/observer.(*Controller).syncHandlerinternal/observer/observer.go:121internal/observer.(*Controller).renderDesiredinternal/observer/observer.go:253internal/observer.computeDiffinternal/observer/drift.go:53internal/observer.objectDiffinternal/observer/drift.go:67internal/observer.normalizeinternal/observer/drift.go:208internal/observer.(*Controller).writeInSyncinternal/observer/status.go:49internal/observer.(*Controller).requestSyncinternal/observer/status.go:83