Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add data source for volume provisioning #2495

Merged
merged 12 commits into from
Aug 25, 2018
148 changes: 148 additions & 0 deletions contributors/design-proposals/storage/data-source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Add DataSource for Volume Operations

Note: this proposal is part of [Volume Snapshot](https://github.com/kubernetes/community/pull/2335) feature design, and also relevant to recently proposed Volume Clone feature.

## Goal
In Volume Snapshot proposal, a snapshot is now represented as first-class CRD objects and an external snapshot controller is responsible for managing its lifecycle. With Snapshot API available, users could provision volumes from snapshot and data will be prepopulated to the volumes. Also considering clone and other possible storage operations, there could be many different types of sources used for populating the data to the volumes. In this proposal, we add a general "DataSource" which could be used to represent different types of data sources.

## Design
### API Change
A new DataSource field is proposed to add to PVC to represent the source of the data which is pre-populated to the provisioned volume. For DataSource field, we propose to define a new type “TypedLocalObjectReference”. It is similar to “LocalObjectReference” type with additional Kind field in order to support multiple data source types. In the alpha version, this data source is restricted in the same namespace of the PVC. The following are the APIs we propose to add.

```

type PersistentVolumeClaimSpec struct {
// If specified, volume will be pre-populated with data from the specified data source.
// +optional
DataSource *TypedLocalObjectReference `json:"dataSource" protobuf:"bytes,2,opt,name=dataSource"`
}

// TypedLocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
type TypedLocalObjectReference struct {
// Name of the object reference.
Name string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which line?

// Kind indicates the type of the object reference.
Kind string
// APIGroup is the group for the resource being referenced
APIGroup string
}

```
### Error Handling
If an external-provisioner does not understand the new DataSource field and cannot populate the data to the volume, we propose to add a PV condition to detect this situation and fail the operation. The idea is simlar to the design of ["Pod Ready++"](https://github.com/kubernetes/community/blob/master/keps/sig-network/0007-pod-ready%2B%2B.md)

First we introduce a condition called "VolumeDataPopulated" into PV. With the feature of snapshot and data source, volume might be created from snapshot source with data populated into the volume instead of an empty one. The external provision needs to understand the data source and also mark the condition "VolumeDataPopualted" to true. The PV controller will check this condition if the data source of PVC is specified. Only if the condition is true, the PVC can be marked as "Bound" phase. In case of an old version of provisioner is in use and it cannot recognize the data source field in PVC, an empty Volume will be provisioned. In this situation, since the "VolumeDataPouplated" condition is not set to true by the provisioner, the PV controller will not mark PVC as "Bound" phase so that user cannot use this PVC yet. We can also add this condition into PVC to tell the users that the PVC's data is not populated.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What ready++ did was make readiness a generic thing. You want to add the readinessGates[] field, and the "ready" signal is when all of the conditions listed in readinessGates are "True". Check @freehan's doc for details about validation required to disallow updates of readinessGates (I forget what we decided in the end).

Copy link
Contributor Author

@jingxu97 jingxu97 Aug 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is possible to make readiness for PV more generic. I think one difference between this PV condition readiness and pod ready++ design is that pod ready++ more focuses on user defined conditions while the PV condition proposed here (DataPopulated) is not the case. For pod, user can specify arbitrary conditions based on their specific needs. For PVC/PV, if user put data sources in their PVC spec, system should check and guarantee this condition by default. So far, we haven't seen the use cases of conditions defined by user side.

With current design, the change is very small (PR kubernetes/kubernetes@8046850) . pv controller will check DataPopulated condition as long as dataSource field is set without any user intervention. If following ready++ pattern, we need to make sure to add the condition by PVC is created (most likely in admission controller).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main thing I am saying is that this is an extension point. It should be extensible. In fact maybe the name of the condition doesn't even need to be codified at all. How does this feel?

  • add readinessGates []string
  • provisioners that need to initialize data as a second step add a readiness gate for themselves
  • provisioners that allocate and init in one step do not need anything
  • PVCs are not ready until all of their readinessGates's Conditions are True
  • same mutability / immutability rules as @freehan work :)

So the real questions I have:

  1. Do we actually have provisioners that do 2-step initalization today which can't hide that fact (e.g. don't create the PV until it is done)?

  2. Can we conceive of any hypothetically plausible other readiness gates for PVC that would use the same mechanism, or could it just be a well-understood bool?


```
// PersistentVolumeStatus is the current status of a persistent volume.
type PersistentVolumeStatus struct {
// Phase indicates if a volume is available, bound to a claim, or released by a claim.
// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#phase
// +optional
Phase PersistentVolumePhase `json:"phase,omitempty" protobuf:"bytes,1,opt,name=phase,casttype=PersistentVolumePhase"`
...

// +optional
Conditions []PersistentVolumeCondition
}

type PersistentVolumeConditionType string

// These are valid conditions of PersistentVolume
const (
// An user trigger resize of pvc has been started
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PersistentVolume rather than pvc?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this condition describes whether data is populated to a PersistentVolume.

The comments should be fixed though. This is not about "resize".

PersistentVolumeDataPopulated PersistentVolumeConditionType = "DataPopulated"
)

type PersistentVolumeCondition struct {
Type PersistentVolumeConditionType
Status ConditionStatus
// +optional
LastTransitionTime metav1.Time
// +optional
Reason string
// +optional
Message string
}
```

## Use cases
* Use snapshot to backup data: Alice wants to take a snapshot of her Mongo database, and accidentally delete her tables, she wants to restore her volumes from the snapshot.
To create a snapshot for a volume (represented by PVC), use the snapshot.yaml

```
apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshot
metadata:
name: snapshot-pd-1
namespace: mynamespace
spec:
source:
kind: PersistentVolumeClaim
name: podpvc
snapshotClassName: snapshot-class

```
After snapshot is ready, create a new volume from the snapshot

```
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: snapshot-pvc
Namespace: mynamespace
spec:
accessModes:
- ReadWriteOnce
storageClassName: csi-gce-pd
dataSource:
kind: VolumeSnapshot
name: snapshot-pd-1
resources:
requests:
storage: 6Gi
```

* Clone volume: Bob want to copy the data from one volume to another by cloning the volume.

```
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: clone-pvc
Namespace: mynamespace
spec:
accessModes:
- ReadWriteOnce
storageClassName: csi-gce-pd
dataSource:
kind: PersistentVolumeClaim
name: pvc-1
resources:
requests:
storage: 10Gi
```

* Import data from Github repo: Alice want to import data from a github repo to her volume. The github repo is represented by a PVC (gitrepo-1). Compare with the user case 2 is that the data source should be the same kind of volume as the provisioned volume for cloning.

```
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: clone-pvc
Namespace: mynamespace
spec:
accessModes:
- ReadWriteOnce
storageClassName: csi-gce-pd
dataSource:
kind: PersistentVolumeClaim
name: gitrepo-1
resources:
requests:
storage: 100Gi
```