Crossplane’s deletion policy on managed resources is a critical safety net that prevents accidental destruction of your cloud infrastructure.
Let’s see this in action. Imagine you have a Kubernetes CompositeResourceDefinition (CRD) for a ProductionDatabase that looks something like this:
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: productiondatabases.database.example.com
spec:
group: database.example.com
names:
kind: ProductionDatabase
plural: productiondatabases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
storageGB:
type: integer
required:
- parameters
status:
type: object
properties:
dbInstanceName:
type: string
And you instantiate it with a CompositeResource (XR):
apiVersion: database.example.com/v1alpha1
kind: ProductionDatabase
metadata:
name: my-production-db
spec:
parameters:
storageGB: 100
When Crossplane reconciles this XR, it will create a Composite resource, which in turn provisions a ManagedResource (MR) like a RDSInstance from the AWS provider. This RDSInstance is the actual cloud resource.
The deletionPolicy is a field you set on the CompositeResource (XR) itself. It dictates what happens to the underlying ManagedResource (and thus the cloud resource) when the XR is deleted.
Here are the common policies and how they work:
-
Orphan(Default): This is the safest default. When you delete the XR, the underlying MR and its cloud resource are not deleted. They are orphaned, meaning they continue to exist independently. This is great for protecting critical infrastructure, but you’ll need to manually clean up the orphaned resources later.Consider this XR with the default policy:
apiVersion: database.example.com/v1alpha1 kind: ProductionDatabase metadata: name: my-production-db spec: parameters: storageGB: 100If you
kubectl delete productiondatabase my-production-db, theRDSInstanceprovisioned by Crossplane will remain in AWS. -
Foreground: This policy ensures that the XR is deleted only after all its owned MRs are successfully deleted. Crossplane will delete the MRs in the order specified by theirdeletionPolicy(which defaults toForegroundif not specified on the MR itself). If any MR fails to delete, the XR deletion will be blocked. This provides a controlled, cascading deletion.To enforce this, you’d explicitly set it on your XR:
apiVersion: database.example.com/v1alpha1 kind: ProductionDatabase metadata: name: my-production-db annotations: crossplane.io/deletion-policy: Foreground # Or set it directly in spec spec: parameters: storageGB: 100When you delete this XR, Crossplane will first try to delete the associated
RDSInstance. Only upon successful deletion of theRDSInstancewill theProductionDatabaseXR be removed from Kubernetes. -
Delete: This is the most aggressive policy. When the XR is deleted, Crossplane immediately attempts to delete all its owned MRs and their corresponding cloud resources. This is useful for ephemeral environments or when you want complete cleanup.Setting this policy on your XR:
apiVersion: database.example.com/v1alpha1 kind: ProductionDatabase metadata: name: my-production-db annotations: crossplane.io/deletion-policy: Delete # Or set it directly in spec spec: parameters: storageGB: 100Deleting this XR will trigger the deletion of the
RDSInstanceand its underlying AWS RDS instance.
The deletionPolicy can also be applied directly to Managed Resources (MRs) like RDSInstance if you need finer-grained control over specific cloud resources, overriding the policy set on the XR. However, setting it on the XR is usually sufficient and more manageable.
When a CompositeResource (XR) is deleted, Crossplane doesn’t just delete the Managed Resources (MRs) it owns. It iterates through the Composition that created the XR, identifies the MRs defined in the resources field of the Composite template, and then applies the deletion policy to those specific MRs. If an MR has its own deletionPolicy set, that takes precedence over the XR’s policy for that specific MR.
The most surprising thing about the deletionPolicy is that it’s not just about deleting resources; it’s fundamentally about managing the lifecycle of your cloud infrastructure as a declarative Kubernetes object. The Orphan policy, by default, ensures that Kubernetes’ imperative delete command on an XR doesn’t lead to an irreversible cloud resource deletion, forcing a more deliberate operational process for infrastructure decommissioning.
You might find that even with Foreground or Delete policies, resources linger. This often happens when the cloud provider’s API is slow to confirm deletion, or if there are external dependencies on the resource that prevent immediate removal. In such cases, Crossplane will continue to attempt deletion, but the XR might appear deleted while its underlying resources are still being cleaned up by the provider.
The next concept you’ll likely encounter is how to manage resource updates and drifts, particularly when using Orphan or Foreground deletion policies.