- Owner: Daniel Mangum (@hasheddan)
- Reviewers: Crossplane Maintainers
- Status: Draft
External Resource
: an infrastructure resource that runs outside of Crossplane (i.e. an S3 Bucket on AWS).Managed Resource
: a Kubernetes resource that is responsible for managing an external resource (receives configuration details from theResourceClass
andResourceClaim
). It is of typeResource
but will be referred to asManaged Resource
consistently here to avoid confusion.ResourceClass
: a Kubernetes resource that contains implementation details specific to a certain environment or deployment, and policies related to a kind of resource.ResourceClaim
: a Kubernetes resource that captures the desired configuration of a resource from the perspective of a workload or application.
Crossplane resource classes allow for a reclaimPolicy
to be set on creation. Acceptable values for reclaimPolicy
are Delete
or Retain
. This value informs Crossplane of how to behave when a Managed Resource
is deleted. If the policy is set to Delete
, the External Resource
will be deleted when the Managed Resource
is deleted, which is generally triggered by the deletion of a Resource Claim
for that Managed Resource
. If set to Retain
, the Managed Resource
will be deleted, but the External Resource
will persist.
Kubernetes introduces the PersistentVolume
, PersistentVolumeClaim
and StorageClass
resources. These roughly map to the following Crossplane resources:
- The external storage asset -->
External Resource
PersistentVolume
-->Managed Resource
StorageClass
-->ResourceClass
PersistentVolumeClaim
-->ResourceClaim
Like Managed Resources
in Crossplane, PersistentVolumes
can have their reclaimPolicy
set directly if they are manually provisioned, or by a StorageClass
if provisioned dynamically. If the PersistentVolume
is provisioned manually, it will keep its reclaimPolicy
throughout its lifecycle even if it is eventually managed by a StorageClass
with a different reclaimPolicy
.
Dynamic provisioning occurs when an administrator has created a StorageClass
and a PersistentVolumeClaim
requests storage by referencing that class or relying on a default StorageClass
. This is similar to a ResourceClaim
referencing a ResourceClass
in Crossplane. In both situations, the Managed Resource
or PersistentVolume
will inherit the reclaimPolicy
of the ResourceClass
or StorageClass
. However, in Kubernetes if no reclaimPolicy
is set on the StorageClass
the PersistentVolume
will default to Delete
, while in Crossplane a ResourceClass
without a specified reclaimPolicy
will cause the Managed Resource
to default to Retain
.
The most significant difference between resources in Crossplane and persistent volumes in Kubernetes is what happens upon deletion. In Kubernetes, the reclaimPolicy
dictates what happens to the PersistentVolume
when a PersistentVolumeClaim
is deleted. In Crossplane, the reclaimPolicy
dictates what happens to the External Resource
when a ResourceClaim
is deleted.
For example, consider the following scenarios:
Kubernetes: A PersistentVolume
exists with a reclaimPolicy
set to Retain
. A PersistentVolumeClaim
that was responsible for the dynamic provisioning of that PersistentVolume
via reference to a StorageClass
is deleted. The reclaimPolicy
of the PersistentVolume
results in the Kubernetes object being retained, and thus the external storage asset being retained.
Crossplane: A Managed Resource
exists with a reclaimPolicy
set to Retain
. A ResourceClaim
that was responsible for the dynamic provisioning of that Managed Resource
via reference to a ResourceClass
is deleted. The reclaimPolicy
of the Managed Resource
results in the Kubernetes object being deleted, but the External Resource
being retained.
In short, reclaim policies in Crossplane manage the relationship between a ResourceClaim
and the External Resource
, while reclaim policies in Kubernetes persistent volumes manage the relationship between the PersistentVolumeClaim
and the PersistentVolume
Kubernetes object.
Generally, resources are provisioned via the following steps:
- A user creates a
ResourceClass
.
apiVersion: core.crossplane.io/v1alpha1
kind: ResourceClass
metadata:
name: standard-aws-bucket
namespace: crossplane-system
annotations:
resource: bucket.storage.crossplane.io/v1alpha1
parameters:
versioning: "false"
cannedACL: private
localPermission: ReadWrite
region: REGION
provisioner: s3bucket.storage.aws.crossplane.io/v1alpha1
providerRef:
name: demo-aws
reclaimPolicy: Delete
- A user creates a
ResourceClaim
.
apiVersion: storage.crossplane.io/v1alpha1
kind: Bucket
metadata:
name: my-bucket
namespace: default
spec:
classRef:
name: standard-aws-bucket
namespace: crossplane-system
name: my-bucket-1234
- The creation of a
ResourceClaim
triggers aManaged Resource
to be created using information from the claim and the referencedResourceClass
. If theResourceClass
provides a value forreclaimPolicy
it will be set on theManaged Resource
. If not, theManaged Resource
will have itsreclaimPolicy
set to its default value. - The
Managed Resource
provisions anExternal Resource
(in this case an S3 bucket) and manages it. - A user deletes the
ResourceClaim
. Because theManaged Resource
has anOwnerReference
to theResourceClaim
, the deletion of theResourceClaim
triggers the deletion of theManaged Resource
. - If the
Managed Resource
reclaimPolicy
is set toRetain
, theManaged Resource
will be deleted, but theExternal Resource
will persist (i.e. the S3 bucket will still exist in your AWS account). If thereclaimPolicy
is set toDelete
both theManaged Resource
and theExternal Resource
will be deleted.
Reclaim policies exist in Crossplane in order to provide the ability for an External Resource
to persist outside of the lifecycle of a ResourceClaim
to which they are bound. However, the current status of reclaim policies is flawed in that it allows for the possibility that an External Resource
that was created by Crossplane persists after the deletion of the Managed Resource
that represents it. This leads to an inaccurate state representation for a system that should be able to serve as the single control plane across cloud providers. Reclaim policies should more closely represent the functionality implemented in Kubernetes Persistent Volumes by tightly coupling the lifecyle of Managed Resources
with their corresponding External Resource
. Motivation for this change is provided by the following core concepts:
- Crossplane should always provide an accurate representation of resource state (including that of external resources)
External Resources
created by Crossplane should always have aManaged Resource
representation unless theManaged Resource
is manually removed by an administrator (i.e. no orphanedExternal Resources
)- A tightly coupled
External Resource
/Managed Resource
pair should have the option to persist after the deletion of anyResource Claim
with which they are bound (i.e. areclaimPolicy
set toRetain
)
A move to change reclaim policies in Crossplane to match that of Kubernetes Persistent Volumes would result in the policies dictating the relationship between ResourceClaims
and Managed Resources
instead of the current status of ResourceClaims
and External Resources
. The only tradeoff in functionality with this shift is that unbound Managed Resources
may continue to exist after deletion of a the ResourceClaim
that they reference if their reclaimPolicy
is set to Retain
. This is opposed to the current system where the Managed Resource
is always deleted upon ResourceClaim
deletion, despite its reclaimPolicy
. However, the persistence of the Managed Resources
actually serves as a feature as they are a reminder that an unbound External Resource
(which may be billing you) exists as well. To clean up the retained unbound Managed Resource
and External Resource
, an administrator will manually delete the Managed Resource
from Crossplane, then take action on the External Resource
.