From 61902ad8ef60a217d6bd36d4f682b5359a9876e9 Mon Sep 17 00:00:00 2001 From: Yinan Li Date: Tue, 26 Mar 2019 10:28:01 -0700 Subject: [PATCH] Added a KEP for the Stateful Application Data Management API --- .../20190326-stateful-application-api.md | 790 ++++++++++++++++++ keps/sig-apps/k8s-stateful-app-mgmt-api.png | Bin 0 -> 53427 bytes 2 files changed, 790 insertions(+) create mode 100644 keps/sig-apps/20190326-stateful-application-api.md create mode 100644 keps/sig-apps/k8s-stateful-app-mgmt-api.png diff --git a/keps/sig-apps/20190326-stateful-application-api.md b/keps/sig-apps/20190326-stateful-application-api.md new file mode 100644 index 00000000000..8752c400c2c --- /dev/null +++ b/keps/sig-apps/20190326-stateful-application-api.md @@ -0,0 +1,790 @@ +--- +title: Kubernetes Stateful Application Data Management API +authors: + - "@liyinan926" +owning-sig: sig-apps +participating-sigs: + - sig-apps + - sig-storage +reviewers: + - "@kow3ns" + - "@saadali" + - "@thockin" +approvers: + - "@kow3ns" + - "@saadali" + - "@thockin" +editor: TBD +creation-date: 2019-03-26 +last-updated: 2019-05-06 +status: provisional +see-also: + - n/a +replaces: + - n/a +superseded-by: + - n/a +--- + +# Kubernetes Stateful Application Data Management API + +## Table of Contents + +* [Kubernetes Stateful Application Data Management API](#kubernetes-stateful-application-data-management-api) + * [Table of Contents](#table-of-contents) + * [Summary](#summary) + * [Motivation](#motivation) + * [Goals](#goals) + * [Non-Goals](#non-goals) + * [Proposal](#proposal) + * [Terminologies](#terminologies) + * [API Structure](#api-structure) + * [Stateful Application](#stateful-application) + * [Application Snapshot](#application-snapshot) + * [Application Rollback](#application-rollback) + * [User Workflows](#user-workflows) + * [Describing a Stateful Application](#describing-a-stateful-application) + * [Taking an Application Snapshot](#taking-an-application-snapshot) + * [Restoring (or Cloning) an Application from a Snapshot](#restoring-or-cloning-an-application-from-a-snapshot) + * [Rolling Back an Application to a Snapshot](#rolling-back-an-application-to-a-snapshot) + * [Controller Workflows](#controller-workflows) + * [Taking an Application Snapshot](#taking-an-application-snapshot-1) + * [Restoring (or Cloning) an Application from a Snapshot](#restoring-or-cloning-an-application-from-a-snapshot-1) + * [Implementation History](#implementation-history) + +[Tools for generating]: https://github.com/ekalinin/github-markdown-toc + +## Summary + +This KEP proposes a Kubernetes Stateful Application Data Management API consisting of a set of [CustomResourceDefinitions (CRD)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) that collectively define the notion of stateful applications, i.e., applications that maintain persistent state, and a set of data management semantics on stateful applications such as snapshot, backup, restoration, and clone. A snapshot of a stateful application is defined as a point-in-time capture of the state of the application, taken in an application-consistent manner. It captures both the application configurations (definitions of Kubernetes resources that make up the application, e.g., StatefulSets, Services, ConfigMaps, Secrets, etc.) and persistent data contained within the application (via persistent volumes). A snasphot can also include optional tags in the form of key-value pairs for extra information about itself. + +## Motivation + +The addition of the [VolumeSnapshot](https://kubernetes.io/docs/concepts/storage/volume-snapshots/) API in Kubernetes 1.12 enables backup and restoration support for persistent volumes. With the [VolumeSnapshot](https://kubernetes.io/docs/concepts/storage/volume-snapshots/) API, users can take a snapshot of a persistent volume or restore a volume fron a snapshot. When it comes to application snapshot and restoration semantics, however, more things need to be considered than just volume snapshots. As stated above, an application snapshot captures both its configurations and persistent data. The key is that an application snapshot contains sufficient information to completely create (from scratch) an instance of a stateful application as captured at a particular point in time. + +Specifically, an application snapshot contains both a copy of the definitions of Kubernetes resources that the application is comprised of and snapshots of persistent volumes used by the application. Particularly, the volume snapshots must be taken at the same time in an application consistent manner. To guarantee application consistency, there may be a need to quiesce the application before taking volume snapshots and unquiesce it after the volume snapshots are successfully taken. The [ExecutionHook](https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/20190120-execution-hook-design.md) proposal a general mechanism for users to request execution of arbitrary hook commands in application containers for use cases such as application quiescing and unquiescing. + +With the [VolumeSnapshot](https://kubernetes.io/docs/concepts/storage/volume-snapshots/) API and [ExecutionHook](https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/20190120-execution-hook-design.md) API, we have some of the necessary building blocks to perform application-level snapshot and restoration operations. However, application-level data management operations require higher-level workflows and automation. For example, taking an application snapshot is a multi-step workflow that does more than orchestrating volume snapshots and hook executions. As of today, there's no API in Kubernetes for application data management truly at the application-level. + +This proposal tries to close the gap by introducing a new Kubernetes API for supporting snapshot, backup, restoration, and clone semantics at the application-level in an application-consistent manner. This new API exposes application-level data management semantics through Kubernetes custom resources and provides a way to orchestrate volume-level snapshot operations and hook executions by automatically managing the lifecycle of `VolumeSnapshot` and `ExevcutionHook` API objects as part of some higher-level workflows. By modeling application snapshots and backups as declarative custom resources, they can be used as data sources for application restoration and cloning. Similarly, connections between snapshots and backups can be expressed to support operations such as exporting snapshots as backups and importing of backups into snapshots. + +### Goals + +* Proposes a Kubernetes API for stateful application data management that supports application-level snapshot, backup, recovery, and clone semantics. + +### Non-Goals + +* Proposes a detailed controller implementation of the new API. + +## Proposal + +### Terminologies + +* **Stateful Application**: a Kubernetes application that maintains persistent state, likely through persistent volumes, and to which data management semantics identified above are applicable. +* **Application Snapshot**: a point-in-time capture of the state of the application, taken in an application-consistent manner and stored locally in a Kubernetes cluster. It consists of two major components: + * Snapshots of a group of relevant persistent volumes used by the application. + * The configuration of the application and its sub-components, captured as a copy of the resource definitions of Kubernetes objects the application is comprised of. +* **Application Backup**: a capture of the state of an application (both configuration and data) that is stored outside of a Kubernetes cluster. This may be an export of a local application snapshot to a remote storage. + +### API Structure + +The diagram below illustrates the overall Kubernetes API structure. Dotted arrows mean association through object names or object references. Solid arrows mean a binding between the two resource types involved. Green colored resources are the user-facing ones, blue colored ones are expected to be created and managed by system administrators, and light red colored ones are normally created as a result of performing the requested operations. + +![API structure](./k8s-stateful-app-mgmt-api.png) + +With this API structure, users can take a snapshot or backup of a `StatefulApplication`, via an `ApplicationSnapshot` or `ApplicationBackup`, respectively. In the reverse direction, both `ApplicationSnapshot`s and `ApplicationBackup`s can be used as data sources in application restoration or clone. An `ApplicationSnapshot` can be exported outside of a cluster as an `ApplicationBackup`, and an `ApplicationBackup` can be imported into the cluster as an `ApplicationSnapshot`. This allows users to use all the stateful application data management semantics in a Kubernetes idiomatic manner. + +Although we introduced the concept of application backups and mentioned the `ApplicationBackup` CRD above, this KEP focuses on details of CRDs related to application snapshot and restoration/clone operations and introduces the following CRDs: +* `StatefulApplication` and `StatefulApplicationClass` for representation and description of stateful applications and for application restoration/clone support, +* and `ApplicationSnapshot`, `ApplicationSnapshotClass`, and `ApplicationSnapshotContent` for application snapshot support, +* and `ApplicationRollback` for application rollback support. + +Details of CRDs related to application backups including `ApplicationBackup`, `ApplicationBackupClass`, and `ApplicationBackupContent` will be introduced in a subsequent KEP or an update to this KEP. + +### Stateful Application + +The API is centered around the notion of stateful applications modeled using a CRD named `StatefulApplication`. The `StatefulApplication` CRD leverages the [Application CRD](https://github.com/kubernetes-sigs/application) for description and aggregation of components and status of an application. Additionally, it supports data management semantics such as snapshot, backup, restoration, and clone for the application it models. + +A `StatefulApplication` object mainly contains the following pieces of information: + +* The name of an `Application` object, which describes an application and contains information to derive the list of Kubernetes resources that the application is comprised of. The `Application` object is assumed to exist in the same namespace. +* An optional data source that can either be a local snapshot of the application or a backup in a remote location, from where the application can be restored or cloned. +* The name of an optional `StatefulApplicationClass` that defines common parameters for a class of `StatefulApplication`s. The parameters are used by the handler when the application is provisioned, e.g., cloned or restored from a data source. See details about `StatefulApplicationClass` below. +* An optional list of `ValueSubstitutionRule`s that define how to substitute old values with new values for certain types of values in the application's Kubernetes resource definitions, when the application is provisioned. + +The following data management operations can be performed on a `StatefulApplication`: + +* Taking a local snapshot of the application and store the snapshot locally within the cluster. +* Taking a backup of the application to a remote location, e.g., a Google Cloud Storage (GCS) or S3 bucket. +* Restoring the application from either a local snapshot within the cluster or a backup in a remote location. +* Cloning the application from either a local snapshot within the cluster or a backup in a remote location. +* Rolling back the application state to that captured in either a local snapshot within the cluster or a backup in a remote location. + +What operation gets triggered for a `StatefulApplication` depends on what values it contains in the two fields above, as the following table summarizes. + +| | Has Data Source | Has no Data Source | +| ------ | ------ | ------ | +| References an Application | No action needed; it's just a wrapper around an `Application` resource. | No action needed; this is not a meaningful combination. | +| References no Application | Creates (clones or restores) the application from the given data source. | No action needed; this state is the result of creating an application from the given data source. | + +The detailed definition of `StatefulApplication` is as follows. + +```go +type StatefulApplicationSpec struct { + // ApplicationClassName is the name of the StatefulApplicationClass to use creating the application, + // e.g., restoring the application from a data source. If this is not specified, the default one of + // the cluster is used. + // +optional + ApplicationClassName *string `json:"applicationClassName,omitempty"` + + // ApplicationName is the name of the Application (https://github.com/kubernetes-sigs/application) + // object, which represents an application and gives the list of Kubernetes resources that make up the + // application in its status. When doing an application restoration, this is the name of the Application + // resource to be created if set. The name of this StatefulApplication resource will be used if this is + // not set. It’s assumed that the Application resource is in the same namespace of it exists. + // +optional + ApplicationName *string `json:"applicationName,omitempty"` + + // Source specifies an optional data source from which the application and its data state is restored. + // +optional + Source *DataSource `json:"source,omitempty"` + + // ValueSubstitutionRules is a set of rules for value substitution when the application is restored + // from a data source. + // +optional + ValueSubstitutionRules []ValueSubstitutionRule `json:"valueSubstitutionRules,omitempty"` +} + +type StatefulApplicationStatus struct { + // Conditions show the current condition of this application. + Conditions []ApplicationCondition `json:"conditions,omitempty"` + + // Source is a reference to the source from which the application was most recently restored or rolled back from. + Source *corev1.TypedLocalObjectReference `json:"source,omitempty"` +} + +// ValueSubstitutionRuleType is the type of ValueSubstitutionRules. +type ValueSubstitutionRuleType string + +// Set of valid values of ValueSubstitutionRuleType. +const ( + ValueSubstitutionRuleTypeName ValueSubstitutionRuleType = "Name" + ValueSubstitutionRuleTypeLabel ValueSubstitutionRuleType = "Label" + ValueSubstitutionRuleTypeAnnotation ValueSubstitutionRuleType = "Annotation" + ValueSubstitutionRuleTypeEnvVar ValueSubstitutionRuleType = "EnvVar" +) + +// ValueSubstitutionRule defines a rule for value sibstitution. +type ValueSubstitutionRule struct { + // Type is the type of this ValueSubstitutionRule. + Type ValueSubstitutionRuleType `json:"type"` + + // Key is an optional key this rule applies to. For example, when the type is Label, this can be used to + // specify the label this rule applies to. Similarly, when the type is Annotation or EnvVar, this can be + // used to specify the annotation or environment variable this rule applies to. + // +optional + Key *string `json:"key,omitempty"` + + // OldValue is the old value to be substituted in the given type of values. + // This may be a pattern in the values. + OldValue string `json:"oldValue"` + + // NewValue is the new value that will be used in place of each occurrence of the OldValue. + // If NewValue is empty, it is considered an intention to remove the key with the OldValue. + NewValue string `json:"newValue"` + + // Selector is an optional label selector for filtering Kubernetes resources to which this rule applies. + // +optional + Selector *metav1.LabelSelector `json:"selector,omitempty"` +} + +// DataSourceType specifies the type of the data source from which the application and its data state is restored. +type DataSourceType string + +// Set of valid values of DataSourceType. +const ( + DataSourceSnapshot DataSourceType = "Snapshot" + DataSourceBackup DataSourceType = "Backup" +) + +// DataSource defines a source from which a StatefulApplication and its data state can be restored. +type DataSource struct { + // Type specifies the type of the data source. + Type DataSourceType `json:"type"` + + // SnapshotRef specifies a reference to an ApplicationSnapshot as the data source for cases of + // restoring an application from a snapshot. This is required when Type is "Snapshot". + // +optional + SnapshotRef *corev1.ObjectReference `json:"snapshotRef,omitempty"` + + // BackupRef specifies a reference to an ApplicationBackup as the data source for cases of + // restoring an application from a backup. This is required when Type is "Backup". + // +optional + BackupRef *corev1.ObjectReference `json:"backupRef,omitempty"` +} + +// ConditionStatus is the status of a condition. +type ConditionStatus string + +// Set of valid values of ConditionStatus. +const ( + ConditionTrue ConditionStatus = "True" + ConditionFalse ConditionStatus = "False" + ConditionUnknown ConditionStatus = "Unknown" +) + +// ApplicationCondition defines a condition of a StatefulApplication. +type ApplicationCondition struct { + // Type is the type of the condition. + Type string `json:"type,omitempty"` + + // Message is a human readable message indicating details about the condition’s last transition. + Message string `json:"message,omitempty"` + + // Reason is the reason for the condition's last transition. + Reason string `json:"reason,omitempty"` + + // Status is the status of this condition. + // +kubebuilder:validation:Enum=True,False,Unknown + Status corev1.ConditionStatus `json:"status,omitempty"` + + // LastTransitionTime is the last time the condition transitioned from one status to another. + LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty"` + + // LastUpdateTime is the last time the condition was updated. + LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"` +} + +type StatefulApplication struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec StatefulApplicationSpec `json:"spec,omitempty"` + Status StatefulApplicationStatus `json:"status,omitempty"` +} +``` + +A `StatefulApplication` object can optionally reference a `StatefulApplicationClass` object by its name. `StatefulApplicationClass` is a cluster-scope CRD that defines the handler and common parameters for a class of `StatefulApplication`s. Below is the definition of `StatefulApplicationClass`. + +```go +type StatefulApplicationClass struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Handler is the name of the controller that should be invoked when a + // StatefulApplication of this class is to be provisioned. + Handler string `json:"handler"` + + // Parameters are opaque parameters to the snapsohtter. + // +optional + Parameters map[string]string `json:"parameters,omitempty"` + + // StorageClassMapping is a mapping of source to target StorageClass names. + // This mapping is used to get the target StorageClasses for PVCs when an + // application of this class is restored from a snapshot or backup. + // Specifically, when an application is restored in cluster B from a snapshot + // taken in cluster A, the StorageClasses in cluster B may be different than + // the ones in cluster A, so a StorageClass used by a class of PVCs in cluster + // A may not exist in cluster B. In this case, there may be an equivalent + // StorageClass in cluster B that can be used instead. This mapping defines + // what alternative StorageClasses to use when a source StorageClass is not + // found. + // +optional + StorageClassMapping map[string]string `json:"storageClassMapping,omitempty"` +} +``` + +### Application Snapshot + +The API has three snapshot-related CRDs, namely, `ApplicationSnapshot`, `ApplicationSnapshotClass`, and `ApplicationSnapshotContent`. `ApplicationSnapshot` is a namespace-scoped CRD for taking a local snapshot of a `StatefulApplication` or importing an `ApplicationBackup` into a local snapshot that can later be used for restoring or cloning an application. The definition of `ApplicationSnapshot` looks like the following. + +```go +type ApplicationSnapshotSpec struct { + // SnapshotClassName is the name of the ApplicationSnapshotClass object to use for snapshot-related operations. + SnapshotClassName string `json:"snapshotClassName"` + + // Source specifies the source from which the snapshot is created. + Source SnapshotSource `json:"source"` + + // Tags are user-specified free texts to attach to the snapshot. + // +optional + Tags map[string]string `json:"tags,omitempty"` + + // PersistentVolumeClaimFilter is a filter for selecting PersistentVolumeClaims of the application to include + // when taking the application snapshot. + // +optional + PersistentVolumeClaimFilter *metav1.LabelSelector `json:"persistentVolumeClaimFilter,omitempty"` + + // Name of the ApplicationSnapshotContent this ApplicationSnapshot is bound to. An auto-generated name is used + // for the new ApplicationSnapshotContent resource create when taking a snapshot, if not specified. + // +optional + SnapshotContentName *string `json:"snapshotContentName,omitempty"` + + // VolumeSnapshotTimeoutSeconds is the timeout in seconds for VolumeSnapshots. + // If not all VolumeSnapshots become ready before the timeout happens, the snapshot process proceeds with + // execution of post-hooks (if any) to unfreeze the application. The Phase is set to Failed in this case. + VolumeSnapshotTimeoutSeconds *int64 `json:"volumeSnapshotTimeoutSeconds,omitempty"` + + // Time to live (TTL) of this resource after the snapshotting completed or failed. The ApplicationSnapshot + // resource will be deleted after the given duration, if this is set. + // +optional + TTL *metav1.Duration `json:"ttl,omitempty"` +} + +type ApplicationSnapshotStatus struct { + // Phease is the current phase of the snapshot process. + Phase SnapshotPhase `json:"phase,omitempty"` + + // LastTransitionTime is the last time the phase transitioned from one to another. + LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty"` + + // Error gives detailed information about the error that caused the failure if the snasphot process failed. + Error *SnapshotError `json:"error,omitempty"` +} + +// SnapshotSourceType specifies the type of the snapshot source from which the snapshot is created. +type SnapshotSourceType string + +// Set of valid values of SnapshotSourceType. +const ( + SnapshotSourceApplication SnapshotSourceType = "Application" + SnapshotSourceBackup SnapshotSourceType = "Backup" +) + +// SnapshotSource specifies the source where the snapshot is created from. +type SnapshotSource struct { + // Type specifies the type of the snapshot source. + Type SnapshotSourceType `json:"type"` + + // ApplicationName specifies the name of a StatefulApplication as the source of the snapshot for cases of taking + // a snapshot of an application. This is required when Type is "Application". + // +optional + ApplicationName *string `json:"applicationName,omitempty"` + + // BackupName specifies the name of an ApplicationBackup as the source of the snapshot for cases of importing a + // snapshot from a backup. This is required when Type is "Backup". + // +optional + BackupName *string `json:"backupName,omitempty"` +} + +// SnapshotPhase represents the current phase of the snapshot process. +type SnapshotPhase string + +// Set of phases the snapshot process can have. +const ( + SnapshotPhaseNew SnapshotPhase = "New" + SnapshotPhaseInProgress SnapshotPhase = "InProgress" + SnapshotPhaseBound SnapshotPhase = "Bound" + SnapshotPhaseFailed SnapshotPhase = "Failed" + SnapshotPhaseFailedValidation SnapshotPhase = "FailedValidation" +) + +// SnapshotError gives detailed information about an error of a snapshot operation. +type SnapshotError struct { + // Time is the time the error occurred. + Time *metav1.Time `json:"time,omitempty"` + // Reason is the reason of the error. + Reason string `json:"reason,omitempty"` + // Message is the detailed message of the error. + Message string `json:"message,omitempty"` +} + +type ApplicationSnapshot struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ApplicationSnapshotSpec `json:"spec,omitempty"` + Status ApplicationSnapshotStatus `json:"status,omitempty"` +} +``` + +`ApplicationSnapshotClass` is a cluster-scoped CRD that defines the snapshotter and common parameters for a class of `StatefulApplication`s. An `ApplicationSnapshot` object must specify the name of an `ApplicationSnapshotClass` object, which identifies the snapshotter and provide needed parameters to the snapshotter. The `ApplicationSnapshotClass` object also defines hooks for quiescing and unquiescing the application. Below is the definition of `ApplicationSnapshotClass`. + +```go +type ApplicationSnapshotClass struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Snapshotter is the name of the snapshot controller that should be invoked. + Snapshotter string `json:"snapshotter"` + + // VolumeSnapshotClassNames is mapping from StorageClass names to the names of the corresponding + // VolumeSnapshotClasses that should be used when creating VolumeSnapshots. The assumption is that + // snapshot of persistent volumes of the same StorageClass is handled by the same snapshotter + // designated by a VolumeSnapshotClass. The default VolumeSnapshotClass is used for PVCs with no + // StorageClass specified and for PVCs with a StorageClass not found in the mapping. + // +optional + VolumeSnapshotClassNames map[string]string `json:"volumeSnapshotClassNames,omitempty"` + + // Parameters are opaque parameters to the snapsohtter. + // +optional + Parameters map[string]string `json:"parameters,omitempty"` + + // PreHooks are an optional list of hooks to run to do application quiescing/flushing before + // taking an application snapshot. The hooks may return application-specific tags in JSON + // formatted key-value pairs, e.g., {“tag1”: “value1”, “tag2”: “value2”}. Each hook in the + // list is for a specific container of the application, and one container can have no more + // than one pre-hook. + // +optional + PreHooks []HookSpec `json:"preHooks,omitempty"` + + // PostHooks are an optional list of hooks to run to do application unquiescing after taking + // an application snapshot. Each hook in the list is for a specific container of the application, + // and one container of the application can have no more than one post-hook. + // +optional + PostHooks []HookSpec `json:"postHooks,omitempty"` + + // DeletionPolicy is the policy on what happens to an ApplicationSnapshotContent resource and the + // local application snapshot it represents when the ApplicationSnapshot resource it is bound to + // is deleted. + // DeletionPolicy set in individual ApplicationSnapshotContent resources takes precedence over this. + // +optional + // +kubebuilder:validation:Enum=Delete,Retain + DeletionPolicy *DeletionPolicy `json:"deletionPolicy,omitempty"` +} + +// HookSpec defines a hook for quiescing or unquiescing an application. +type HookSpec struct { + // Name is the name of the hook. + Name string `json:"name"` + + // PodFilter is an optional label selector for filtering the pods to execute the hook in. + // +optional + PodFilter *metav1.LabelSelector `json:"podFilter,omitempty"` + + // Container specifies the name of the container to execute the hook in. If not specified, the first + // container is selected. + // +optional + Container *string `json:"container,omitempty"` + + // ActionName specifies the name of the HookAction that defines the action to take for this hook. + // The HookAction resource type is proposed in https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/20190120-execution-hook-design.md#implementation-history. + ActionName string `json:"actionName,omitempty"` +} + +// DeletionPolicy defines the policy on what happens to an ApplicationSnapshotContent resource and the +// local application snapshot it represents when the ApplicationSnapshot resource it is bound to is deleted. +type DeletionPolicy string + +// Set of DeletionPolicy values. +const ( + DeletionPolicyDelete DeletionPolicy = "Delete" + DeletionPolicyRetain DeletionPolicy = "Retain" +) +``` + +`ApplicationSnapshotContent` is a cluster-scoped CRD that describes the details about a local application snapshot. An `ApplicationSnapshotContent` object is created as the result of successfully processing an `ApplicationSnapshot`. The relationship between an `ApplicationSnapshot` object and an `ApplicationSnapshotContent` object is like the relationship between a `VolumeSnapshot` object and a `VolumeSnapshotContent` object. Below is the definition of `ApplicationSnapshotContent`. + +```go +type ApplicationSnapshotContentSpec struct { + // SnapshotClassName is the name of the ApplicationSnapshotClass object to use for snapshot-related operations. + SnapshotClassName string `json:"snapshotClassName"` + + // SnapshotRef is an reference to the ApplicationSnapshot resource this ApplicationSnapshotContent resource is + // bound to. When specified, this creates a bi-directional binding between an ApplicationSnapshot resource and + // this ApplicationSnapshotContent resource. + // +optional + SnapshotRef *corev1.ObjectReference `json:"snapshotRef,omitempty"` + + // VolumeSnapshotRefs is mapping from PVC names to references to the corresponding VolumeSnapshot objects created + // for taking snapshots of individual persistent volumes mounted by the application when the snapshot source is + // a StatefulApplication. + // +optional + VolumeSnapshotRefs map[string]corev1.ObjectReference `json:"volumeSnapshotRefs,omitempty"` + + // Tags are user-specified free texts to attach to the snapshot. This combines user-specified tags in the + // ApplicationSnapshot and tags returned by pre-hooks. + // +optional + Tags map[string]string `json:"tags,omitempty"` + + // MetadataHandle is the handle to persisted application metadata. It contains information needed to read the + // metadata back. + // +optional + MetadataHandle *MetadataHandle `json:"metadataHandle,omitempty"` + + // DeletionPolicy is the policy on what happens to an ApplicationSnapshotContent resource and the + // local application snapshot it represents when the ApplicationSnapshot resource it is bound to + // is deleted. + // DeletionPolicy set here takes precedence over the one (if set) in ApplicationSnapshotClass, if set. + // +optional + // +kubebuilder:validation:Enum=Delete,Retain + DeletionPolicy *DeletionPolicy `json:"deletionPolicy,omitempty"` +} + +type ApplicationSnapshotContentStatus struct {} + +// MetadataHandleType is the type of the application metadata handle. +type MetadataHandleType string + +// Set of valid MetadataHandleType values. +const ( + MetadataHandleOnDisk = "OnDisk" +) + +// MetadataHandle is a handle to persisted application metadata, which includes +// specs of Kubernetes resources that make up an application. +// TODO: complete this when extending the storage options of application metadata. +type MetadataHandle struct { + // Type is the type of the MetadataHandle. + Type MetadataHandleType `json:"type"` + + // OnDisk is a type of application metadata handles that store metadata on disk. + OnDisk *OnDiskHandle `json:"onDisk,omitempty"` +} + +// OnDiskHandle is a type of application metadata handles that store metadata on disk. +type OnDiskHandle struct { + Directory string `json:"directory"` +} + +type ApplicationSnapshotContent struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ApplicationSnapshotContentSpec `json:"spec,omitempty"` + Status ApplicationSnapshotContentStatus `json:"status,omitempty"` +} +``` + +### Application Rollback + +To support application rollback, we propose a namespace-scoped CRD named `ApplicationRollback` that allows uers to rollback an existing `StatefulApplication` to a previous state captured in an `ApplicationSnapshot` or `ApplicationBackup`. Unlike restoration or clone operations, both of which create a new application from scratch, rollback operations update an existing application. Instead of reusing the `StatefulApplication` CRD, we come up with this dedicated CRD because of this difference. More specifically, although we could treat a `StatefulApplication` with both the `applicationName` field set to point to an existing `Application` object and the `source` field set to reference a valid data source as a indication of a user intention to rollback the application, the same could also be the result state after the application was successfully restored or cloned. In the latter case, an `Application` object named after `applicationName` was created as the result of the restoration or clone. So to avoid such confusion, a dedicated CRD is used for rollback operations. Below is the definition of `ApplicationRollback`. + +```go +// ApplicationRollbackSpec defines the desired state of ApplicationRollback +type ApplicationRollbackSpec struct { + // SnapshotClassName is the name of the ApplicationSnapshotClass object to use for snapshot-related operations. + SnapshotClassName string `json:"snapshotClassName"` + + // ApplicationName is the name of the StatefulApplication object that represents the application to rollback. + ApplicationName string `json:"applicationName"` + + // Source specifies an optional data source that contains application metadata and persistent data that + // the application is rolled back to. + Source DataSource `json:"source"` +} + +// ApplicationRollbackStatus defines the observed state of ApplicationRollback +type ApplicationRollbackStatus struct { + // Phease is the current phase of the rollback process. + Phase RollbackPhase `json:"phase,omitempty"` + + // LastTransitionTime is the last time the phase transitioned from one to another. + LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty"` + + // VolumeGroupRollbackName is the name of the VolumeGroupRollback resource created to perform volume + // group rollback when the rollback source is an ApplicationSnapshot. + VolumeGroupRollbackName *string `json:"volumeGroupRollbackName,omitempty"` + + // Error gives detailed information about the error that caused the failure if the rollback process failed. + Error *RollbackError `json:"error,omitempty"` +} + +// RollbackPhase represents the current phase of the rollback process. +type RollbackPhase string + +// Set of phases the rollback process can have. +const ( + RollbackPhaseNew RollbackPhase = "New" + RollbackPhaseInProgress RollbackPhase = "InProgress" + RollbackPhaseCompleted RollbackPhase = "Completed" + RollbackPhaseFailed RollbackPhase = "Failed" + RollbackPhaseFailedValidation RollbackPhase = "FailedValidation" +) + +// RollbackError gives detailed information about an error of a rollback operation. +type RollbackError SnapshotError + +type ApplicationRollback struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ApplicationRollbackSpec `json:"spec,omitempty"` + Status ApplicationRollbackStatus `json:"status,omitempty"` +} +``` + +### User Workflows + +This section talks about how users use the API to perform application snapshot, restoration, clone, and rollback operations, with an example application based on [MongoDB](https://www.mongodb.com/). + +#### Describing a Stateful Application + +A stateful application is modeled using a `StatefulApplication` object that references an `Application` object by its name. The `Application` object describes the metadata and topology information about the application, e.g., the groups and kinds of Kubernetes resources the application is comprised of. The `StatefulApplication` object enables data management semantics for the application described by the `Application` object. Below is an example showing the `StatefulApplication` and `Application` definitions for a simple MongoDB application. + +```yaml +apiVersion: app.k8s.io/v1beta1 +kind: Application +metadata: + name: mongo + namespace: default + labels: + app.kubernetes.io/name: "mongo" +spec: + selector: + matchLabels: + app.kubernetes.io/name: "mongo" + componentKinds: + - group: "" + kind: Service + - group: apps + kind: StatefulSet +--- +apiVersion: app.k8s.io/v1alpha1 +kind: StatefulApplication +metadata: + name: mongo + namespace: default +spec: + applicationName: mongo # name of the Application object +``` + +#### Taking an Application Snapshot + +Before a snapshot can be taken for a `StatefulApplication`, an `ApplicationSnapshotClass` object must exist for the class the `StatefulApplication` belongs to. Below is an example `ApplicationSnapshotClass` for applications that use MongoDB. Note that this object is cluster-scoped so doesn't have `namespace` specified. + +```yaml +apiVersion: apps.k8s.io/v1alpha1 +kind: ApplicationSnapshotClass +metadata: + name: mongo-class +snapshotter: generic-app-snapshotter +deletionPolicy: Delete +preHooks: +- name: lock + actionName: mongo-pre-action +postHooks: +- name: unlock + actionName: mongo-post-action +``` + +And below are the definitions of the pre and post [HookActions](https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/20190120-execution-hook-design.md#proposal) referenced by `mongo-class`, which define commands to lock and unblock a MongoDB database, respectively. + +```yaml +apiVersion: apps.k8s.io/v1alpha1 +kind: HookAction +metadata: + name: mongo-pre-action +spec: + action: + exec: + command: + - "mongo" + - "--eval" + - '"printjson(db.fsyncLock())"' +--- +apiVersion: apps.k8s.io/v1alpha1 +kind: HookAction +metadata: + name: mongo-post-action +spec: + action: + exec: + command: + - "mongo" + - "--eval" + - '"printjson(db.fsyncUnlock())"' +``` + +To take a snapshot of a `StatefulApplication`, a user creates an `ApplicationSnapshot` resource that references the `StatefulApplication` object above in the `source` field, and expects the creation of both a set of `VolumeSnapshot` objects and an `ApplicationSnapshotContent` resource. + +```yaml +apiVersion: apps.k8s.io/v1alpha1 +kind: ApplicationSnapshot +metadata: + name: mongo-snapshot + namespace: default +spec: + snapshotClassName: mongo-class + snapshotContentName: mongo-snapshot-content + tags: + "mongo-version": "4.0" + source: + type: Application + applicationName: mongo # name of the StatefulApplication object + volumeSnapshotTimeoutSeconds: 300 +``` + +#### Restoring (or Cloning) an Application from a Snapshot + +To restore (or clone) an application from a snapshot, a user creates a new `StatefulApplication` resource with optionally the name of the restored application (which will become the name of the `Application` resource of the restored application) and a source pointing to an `ApplicationSnapshot` resource. The user expects the creation of the Kubernetes resources (including `PersistentVolumeClaims` if any) that make up the application and an `Application` resource. + +```yaml +apiVersion: apps.k8s.io/v1alpha1 +kind: StatefulApplication +metadata: + name: mongo-restore + namespace: ns2 # target namespace of the restored application +spec: + applicationName: mongo-clone # name of the Application object + source: + type: Snapshot + snapshotRef: + name: mongo-snapshot + namespace: ns1 + valueSubstitutionRules: + - type: Name + oldValue: mongo + newValue: mongo-clone + - type: Label + key: "app.kubernetes.io/name" + oldValue: mongo + newValue: mongo-clone +``` + +Note that the definition above specifies two `ValueSubstitutionRules` that replaces `mongo` in names and values of label `app.kubernetes.io/name` in the application's Kubernetes resources with `mongo-clone`. Note that all appearances of label `app.kubernetes.io/name` are considered, including those in label selectors of certain resources, e.g., StatefulSets and Services. + +An application may be restored or cloned into a namespace that is different than the one it used to run and in which the snapshot or backup used for restoration or clone was taken. This requires support for cross-namespace transfer of `VolumeSnapshot`s, which is proposed in this [KEP](https://github.com/kubernetes/enhancements/pull/643). + +#### Rolling Back an Application to a Snapshot + +To rollback a `StatefulApplication` to a previous state captured in an `ApplicationSnapshot`, a user creates an `ApplicationRollback` object with the name of the `StatefulApplication` to rollback and a reference to the `ApplicationSnapshot` object in the `source` field. + +```yaml +apiVersion: apps.k8s.io/v1alpha1 +kind: ApplicationRollback +metadata: + name: mongo-rollback + namespace: default +spec: + applicationName: mongo # name of the StatefulApplication object + snapshotClassName: mongo-class + source: + type: Snapshot + snapshotRef: + name: mongo-snapshot + namespace: default +``` + +This operation rolls back both the configuration and persistent data of the application to the state captured in the `ApplicationSnapshot`. Specifically, it rolls back the relevant persistent volumes to their previous states captured in the `VolumeSnapshot`s that are parts of the snapshot artifacts. It also updates the the application's Kubernetes resource specifications to the ones captured in the `ApplicationSnapshot`. + +### Controller Workflows + +Although this KEP does not try to propose a detailed controller implementation for the new API, it's worth talking about the controller workflows at a high-level for the various data management operations introduced above. Note that properly rolling back a `StatefulApplication` to a previous state captured by an `ApplicationSnapshot` requires volume-level rollback support, which is not available yet. So we will not cover the high-level controller workflow for application rollback operation in this KEP. + +#### Taking an Application Snapshot + +At a high-level, taking an `ApplicationSnapshot` of a `StatefulApplication` consists of the following steps: + +1. Identifies the set of Kubernetes resources the application is comprised of, e.g., StatefulSets, Services, ConfigMaps, etc., and the set of `PersistentVolumeClaim`s (PVC) used by the application. +2. Reads and snapshots the definitions of the resources and PVCs identified in step 1. +3. Creates an `ExecutionHook` object for each of the pre-hooks defined in the `ApplicationSnapshotClass` to trigger execution of the pre-hook sequentially. +4. Waits for the execution of the pre-hooks to complete. +5. Creates a `VolumeSnapshot` object for each relevant PVC used by the application. +6. Waits for the `VolumeSnapshot`s to become ready to be used. +7. Creates an `ExecutionHook` object for each of the post-hooks defined in the `ApplicationSnapshotClass` to trigger execution of the post-hook sequentially. +8. Waits for the execution of the post-hooks to complete. +9. Creates an `ApplicationSnapshotContent` object and binds it to the `ApplicationSnapshot` object. + +#### Restoring (or Cloning) an Application from a Snapshot + +Restoring (or cloning) a `StatefulApplication` from an `ApplicationSnapshot` consists of the following steps: + +1. Retrieves the definitions of Kubernetes resources and PVCs of the application stored as part of the snapshot, based on information about the storage of this metadata in the `ApplicationSnapshotContent` object. +2. Creates the set of new PVCs based on the PVC definitions retrieved in step 1. The new PVCs are given data sources that point to the `VolumeSnapshot`s referenced in the `ApplicationSnapshotContent` object. +3. Creates the Kubernetes resources of the restored/cloned application based on resource definitions retrieved from step 1. +4. Creates an `Application` object for the restored/cloned application, which groups Kubernetes resources of the application. + +## Implementation History + +TBD. \ No newline at end of file diff --git a/keps/sig-apps/k8s-stateful-app-mgmt-api.png b/keps/sig-apps/k8s-stateful-app-mgmt-api.png new file mode 100644 index 0000000000000000000000000000000000000000..e69b3ac3a9d09d451fd0104c293415f2dc624177 GIT binary patch literal 53427 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