Skip to content

Commit

Permalink
updating for review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins committed Mar 14, 2023
1 parent d8536f6 commit 85d0693
Showing 1 changed file with 48 additions and 9 deletions.
57 changes: 48 additions & 9 deletions _ap/17/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ tags:

## Intent

Define a pattern for fleet shard status representation and interpretation.
Define a pattern for fleet shard status representation and interpretation. The pattern addresses common problems such as interpreting errors as either temporary or terminal failures.

## Motivation

A fleet shard must convey the status of the data plane resources it is responsible for back to the control plane. This is typically done using mechanisms built around the Kubernetes status sub-resource. There should be consistency around the design and usage of that status information that conforms to Kubernetes guidelines and so that control planes, SREs, and developers can quickly and appropriately reason over the status.
A control plane (or fleet manager) communicates the desired state of resource(s) to a fleet shard. In return the fleet shard must convey the status of the data plane resources it is responsible for back to the control plane. This is typically done using mechanisms built around a Kubernetes https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/[custom resources] and its status sub-resource.

There should be consistency around the design and usage of that status information that conforms to Kubernetes guidelines and so that control planes, SREs, and developers can quickly and appropriately reason over the status.

## Status Guidelines

Expand Down Expand Up @@ -60,15 +62,17 @@ status:

### Interpretation

The meaning of any condition or status field is up to the controller / resource and should be a documented part of the API contract.
The meaning of any condition or status field is up to the controller / resource and should be a documented part of the API contract. Given that the fleet manager is the primary consumer of the status, care should be taken to ensure the control plane's understanding of the status - and any changes must be made with its usage in mind.

For example the ManagedKafka status Ready condition refers to the operator’s view of the resource. A ManagedKafka is only ready when all of the dependent resources are observed to be in their desired / ready state. This will not always be the same notion of readiness from an end user’s observation of managed kafka service. In particular, the restart of a broker pods, a temporary networking issue, etc. may not be reflected in ManagedKafka status. It follows that a ManagedKafka status Ready condition alone is insufficient to show the user the state of their service. ManagedKafka canary and other kafka metrics provide a more exact, and up-to-date, representation of cluster functioning.

For example the ManagedKafka status Ready condition refers to the operator’s view of the resource. A ManagedKafka is only ready when all of the dependent resources are observed to be in their desired / ready state. This will not always be the same notion of readiness from an end user’s observation of managed kafka service. In particular, the restart of a broker pods, a temporary networking issue, etc. may not be reflected in ManagedKafka status. It follows that a ManagedKafka status Ready condition alone is insufficient to show the user the state of their service. ManagedKafka canary and other kafka metrics provide a more exact representation of cluster functioning.
A concrete example with ManagedKafka is that when the IngressController HAProxy pods restart that is not reflected in the ManagedKafka Ready status, but may be interruptive of the user's experience of the service as all existing connections will need to reconnect.

### Error States

An operator in a fleetshard _usually_ lacks sufficient context to determine whether a valid resource is in a terminal state. The operator’s job is simply to implement the desired state whenever possible. For example, if at a given time additional resources are needed, other necessary system parts aren’t installed, etc. - it doesn’t mean the conditions won’t be correct at a later time as a result of some action outside the context of the operator.
An operator in a fleetshard _usually_ lacks sufficient context to determine whether a valid resource is in a terminal state. The operator’s primary job is to maintain the desired state of its resource. If at a given time additional resources are needed, other necessary system parts aren’t installed, etc., there is little or nothing under the operator's direct control that can be done to address the situation. Conditions may be corrected at a later time as a result of some action outside the context of the operator - such as an auto-scaling node coming up.

In cases where the operator does have sufficient context to determine terminality, for example violation of preconditions in installed versions of APIs, then it is acceptable for the operator and the status handling to assume the resource is in a terminal state.
Viewing the operator from a service perceptive means that some situations may be seen as terminal problems. For example with ManagedKafka there are pre-configured instance profiles, such as Developer and Standard, known to both the fleet shard and manager. If the ManagedKafka resource from the control plane specifies a unknown profile, then from a service perspective this may be considered a terminal error and may be given a different reason than other errors. From a more general operator / controller perspective, this situation is not terminal in the sense that the user may not have yet updated the ManagedKafkaAgent resource containing the relevant profile information - once updated the ManagedKafka reconciliation would continue as expected.

When status is conveying an error that is not known to be terminal, it follows that the error may resolve on its own with additional time. Control planes should assume such errors are ephemeral and not immediately react as if a hard failure has occurred. If there are further actions that the control plane may take, the condition reason or other status fields should make that easy to determine. This allows the data plane logic to remain straightforward and not have to fully understand every possible error condition.

Expand All @@ -87,23 +91,58 @@ status:

Rather than interpreting this as a hard failure, it should be assumed that with additional time and reconciliations that it may resolve on its own.

How much time to give an error to resolve is up to the control plane and relevant SLOs. During installation this may include waiting until the SLO has been exceeded. For other operations it may mean waiting at least 1 additional resolution time window if the operator or dependent operators uses a time based mechanism.
How much time to give an error to resolve is up to the control plane and relevant SLOs. During installation this may include waiting until the SLO has been exceeded. For other operations it may mean waiting at least 1 additional resolution time window if the operator or dependent operators uses a time based mechanism.

Enforcement and actions related to SLO timeouts are best for the control plane to consider - for example the control plane may need to try a different cluster for the placement of the resource, which is an action beyond the scope of a single data plane.

### Current vs. Desired State

Especially in instances where spec changes are rolled into dependent resources the desired state will not be fully realized until some point in the future. It is appropriate for the status to provide additional information about this transition. As per the Kubernetes guidelines that could be represented via a condition, or similar to the standard Deployment resource additional status fields such as ready or available replicas, allow for the control plane or a user to infer the progress of the transition.

For example the upgrade of ManagedKafka kafka version requires a rolling update of brokers where each broker is taken off-line and replace with one that has an updated version. This is a relatively long-running process. The status ManagedKafka Ready condition during this time will have a reason of KafkaUpdating, rather than simply indicating Ready based upon the Strimzi Kafka resource being updated to the desired state.

[source,yaml]
----
status:
conditions:
- lastTransitionTime: '2022-08-02T08:24:04.818994Z'
message: 'Updating Kafka version'
status: 'True'
reason: 'KafkaUpdating'
type: Ready
----

So while the desired state has already been applied and we're still Ready, the Reason allows consumers of the status to discern that an upgrade is still in progress.

### generation and observedGeneration

In kubernetes, each object should have a `metadata.generation` field which is defined as a sequence number - set by the system and monotonically increased per resource on a spec change. Some resources include a field named `status.observedGeneration`, which is the generation most recently observed by the component responsible for acting upon changes to the desired state of the resource. This can be used, for instance, to ensure that the reported status reflects the most recent desired state. The observedGeneration field is also part of metav1.Conditions and represents the spec generation that the condition was set based upon.

Similar concepts with fields that mirror their kubernetes couterparts can be introduced to MAS resources to offer a standard way for clients and control planes to figure out when a specific desired state has been taken into account.
Similar concepts with fields that mirror their kubernetes couterparts can be introduced to MAS resources to offer a standard way for clients and control planes to figure out when a specific desired state has been taken into account. Consider the following example of a resource local to the data plane:

[source,yaml]
----
metadata:
annotations:
fleetGeneration: 4
generation: 2
spec:
...
status:
conditions:
- lastTransitionTime: '2022-08-02T08:24:04.818994Z'
message: 'Exceeded timeout of 420000ms while waiting for Pods resource ninth-zookeeper-0 in namespace kafka-cbfv5rnfnecdu9rb4gc0 to be ready'
status: 'False'
reason: 'Error'
type: Ready
fleetObservedGeneration: 3
----

Here the data plane has picked up the 4th generation of the resource from the control plane. The status condition indicates that the fleetObservedGeneration is still at 3. Thus observers, including the control plane, would be able to determine the status condition does not yet reflect the latest desired state. Note that the fleet generation mechansim, shown here as 2, is a separate sequence from the local generation - as it's entirely possible for the fleet shard to miss control plane generations. If desired the local observedGeneration could be in the status as well.

### Frequency Of Status Changes

Rapid changes to a status should be avoided. Each status change is an update that the local Kuberentes instance must process and is generally also relayed to the control plane, which can lead to a substantial amount of overhead for a large number of resources. For controllers that implement fixed interval resolving this is generally not an issue. Event driven controllers though should be designed to minimize unnecessary updates - in particular updates which do not imply a status change should leave the existing status unmodified.
Rapid changes to the status not due to modifications of the custom resource should be avoided. Each status change is an update that the local Kuberentes instance must process and is generally also relayed to the control plane, which can lead to a substantial amount of overhead for a large number of resources. For controllers that implement fixed interval resolving this is generally not an issue. Event driven controllers though should be designed to minimize unnecessary updates - in particular updates which do not imply a status change should leave the existing status unmodified.

## Participants
* Control Plane -- development team for the KAS Fleet Manager API.
Expand Down

0 comments on commit 85d0693

Please sign in to comment.